如何透明地将原生JavaScript变量转换为反应式Meteor变量?

时间:2015-08-12 18:35:05

标签: javascript meteor

当原生变量发生变化时,不会重新运行跟踪器计算:

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

此代码只执行一次:

  

foo是:
  '富'

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

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

当然我不能简单地写:

foo = new ReactiveVar(foo);

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

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

这也会中断,因为obj.foo现在完全不同了,而obj.foo的代码是一个简单的非反应值会立即中断。
它对模块模式(对obj.foo的隔离引用)也毫无用处,并且会导致更多的失步,更多的痛苦甚至更多的麻烦。

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

1 个答案:

答案 0 :(得分:4)

这两种情况,原生变量和对象字段,需要分开进行,它们需要不同的方法。第一个将使用一个简单而又肮脏的技巧,第二个将使用更高级的技巧 让我们从原生变量案例开始。

对象字段

如果变量是可写对象字段,那么我们可以将对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。今天太年轻了,我不会从中抽出一个例子。

变量

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

此类民意调查的例子:

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; });

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

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