【问题标题】:How to transparently turn a native JavaScript variable into a reactive Meteor variable?如何透明地将原生 JavaScript 变量转换为反应式 Meteor 变量?
【发布时间】:2015-08-12 18:35:05
【问题描述】:

本机变量更改时不会重新运行跟踪器计算:

var foo = 'foo';
Tracker.autorun(function logFoo() { console.log('foo is:', foo); });

这段代码只会执行一次:

foo 是:
'富'

计算没有依赖关系,没有_onInvalidateCallback。它几乎已经死了。

然而,在很多情况下,我确实需要原生 JavaScript 变量或对象字段以某种方式在 Tracker 计算中响应式运行(原生 API 未完全移植到 Meteor,...)

当然不能简单写:

foo = new ReactiveVar(foo);

由于我将打破当前帧的引用,其他函数可能会使用 foo 的另一个引用,从而导致不同步和痛苦和头痛。
以类似的方式...

obj.foo = new ReactiveVar(obj.foo);

这也会中断,因为 obj.foo 现在完全不同了,并且依赖于 obj.foo 的代码是一个简单的、非反应性的值将立即中断。
对于模块模式(对obj.foo 的孤立引用),它也没有用,并且会导致更多的不同步和更多的痛苦,甚至更多的头痛。

如何在不破坏遗留代码的情况下将原生 Javascript 变量或对象字段正确更改为 Reactive-Var?

【问题讨论】:

    标签: javascript meteor


    【解决方案1】:

    本地变量和对象字段这两种情况需要分开处理,它们需要不同的方法。第一个将使用简单但肮脏的技巧,第二个将使用更高级的技巧。
    让我们从原生变量 case 开始。


    对象字段

    如果变量是可写对象字段,那么我们可以更改对make a custom get/set couple 的引用,该引用链接到闭包中的反应变量。
    就这么简单:

    function reactivise(obj, field) {
      var rvar = new ReactiveVar(obj[field]);
    
      Object.defineProperty(obj, field, {
        get : function() {
          return rvar.get();
        },
        set : function(value) {
          rvar.set(value);
          return value;
        }
      })
    }
    

    而且它确实有效。使用obj.foo 的本机代码不会注意到更改(除非他们检查属性描述符,但这是一件很奇怪的事情)。但是,响应式计算将因更改此字段而失效。
    但是,它对模块模式很弱(引用隔离以防止损坏)。这是此类模块的示例:

    (function logFoo(foo) {
      console.log(foo);
    }(obj.foo);
    

    这段代码不会关心你是否改变了getter或setter,它已经保存了引用。

    可能有办法解决这个问题......但在撰写本文时,它几乎是炼金术。一个可以提供帮助的 ES7 特性:Object.observe。今天太年轻了,我就不举个例子了。


    变量

    如果您要观察的不是非模块化对象字段(上面的示例),那么我知道的唯一解决方案就是轮询。
    基本上,定期检查值是否发生变化,并为此设置一个 new 反应变量(我们失去了透明度)。

    此类轮询示例:

    function reactivePoll(getter) {
      var rPoll = new ReactiveVar(getter());
    
      Meteor.setInterval(function pollVariable() {
        var newValue = getter();
        if(!_.isEqual(rPoll.curValue, newValue)) {
          rPoll.set(newValue);
        }
      }, 100);
    
      return rPoll;
    }
    

    我们需要让它工作的不是变量引用本身 (foo),而是这个变量的 getter。这是因为如果稍后在代码中更改了 foo 引用,我们的函数将不会意识到这一点(更痛苦的非同步头痛)。
    另外,我们每次都必须检查深度相等,以确保在我们导致失效之前该值确实发生了变化,因为如果 Tracker 看到非原始值,它将自动失效。

    使用示例:

    var reactiveFoo = reactivePoll(function getFoo() { return foo; });
    

    它当然也适用于对象字段。
    请注意,示例代码不具有任何类型的停止机制。它将永远运行,可能会引发内存泄漏、崩溃、减慢您的应用程序并导致剧烈的头痛。不要在生产应用程序中使用它,对其进行调整以更好地控制间隔。


    最安全的选择是基本的脏轮询,即使这意味着更多的负载和防止内存泄漏所需的完整控制。

    【讨论】:

      猜你喜欢
      • 2010-12-12
      • 1970-01-01
      • 2016-11-29
      • 2018-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多