Tracker.autorun如何选择计算?

时间:2014-10-14 07:05:50

标签: meteor

看看Tracker.autorun,这主要是神奇地工作......但我想知道它是如何决定哪些变量将形成计算的依赖。它只选择"反应" vars,例如以下内容:

  window.bar = 1
  Tracker.autorun (c) =>
    bar = window.bar
    foo = Session.get('foo')
    console.log('autorun', foo, bar)

如果我更改Session.set('foo')的值,这将导致计算再次运行。 而只是改变window.bar并不会导致重新运行。如果我使用订阅结果(不是集合),这也有效,所以我猜也是反应性的。

是否有任何指南可以更好地理解这种行为?

编辑:

感谢下面的评论,澄清计算是可以推断的,因为访问器用于反应变量,因此流星可以跟踪deps。

但是我需要更清楚一点来理解var被标记的时间。例如,在下面的示例中,subscribe调用位于autorun之外,但它将结果放入数组中。这意味着Tracker不仅跟踪对(reactive var)访问器方法的调用,而且还跟踪块中引用的任何变量 - 即使设置这些方法的调用都在autorun()块之外。

  subList = [
    Meteor.subscribe("Players"),
    Meteor.subscribe("Stuff" )
  ]

  Tracker.autorun (c) =>
    subReady = _.filter subList, (item) ->
      return item.ready()
    allDone = (subList.length == subReady.length)
    # this code will rerun when the subs ready() are true

也许我应该将其添加为一个新问题......它与this question有关。

2 个答案:

答案 0 :(得分:5)

我不是专家,也没有多多关于它的内容,但我可以尝试简要解释一下。


所有反应变量都有一个称为依赖的东西。例如,当创建新的ReactiveVar时,会创建新的依赖关系。 See here

要从反应变量中检索值,必须调用函数。在“getter”中,指示依赖项记住它具有依赖性。例如,ReactiveVar.get的{​​{3}}。

要更改反应变量的值,必须调用函数。在“setter”中,依赖关系被通知某些内容已发生变化,并且表明依赖于依赖项的所有函数必须重新运行。例如,ReactiveVar.set的{​​{3}}。


不复杂吧?嗯,这只是一个简单的部分,现在剩下的就是建立使其工作的基础设施:)这就更难解释了。

反应变量本身不具有反应性;必须在反应环境中对它们进行评估才能产生反应。通过调用Tracker.autorun创建响应环境。 see here

当您调用Tracker.autorun时,传递给它的函数将在新的响应环境中执行,并且环境将跟踪反应变量通过depend方法通知的所有依赖项。当您调用aDependency.depend时,将执行see here,并且它会依赖于它依赖的依赖项将依赖项添加到环境列表中。

当反应变量改变其值时,将执行See here。它告诉环境它所依赖的一个反应变量已经改变,并使环境中的所有依赖项无效。发生这种情况后,将重新运行传递给Tracker.autorun的整个函数,并跟踪新的依赖项。

你了解全局吗?它的实现比我解释的要复杂一些,但我认为它的工作方式很有用。

答案 1 :(得分:4)

请注意,无论何时访问反应变量,都是通过函数调用,如Session.get(...)collection.find(...).fetch()Meteor.status()。类似Session.get的函数不仅获取Session变量的值,而且还注册对当前计算的依赖(当前计算是动态范围的,因此Session.get知道它是从自动运行中调用的)。

以下是使用Tracker.Dependency

实现自己的反应变量的方法
dependency = new Tracker.Dependency()
currentValue = null

@setCurrentValue = (newValue) ->
  if newValue isnt currentValue
    # rerun computations which depend on this Dependency
    dependency.changed()

    currentValue = newValue

@getCurrentValue = ->
  # register this dependency on the current computation (if there is one)
  dependency.depend()

  return currentValue

以下是你如何使用它:

setCurrentValue("hello")
Tracker.autorun ->
  console.log(getCurrentValue())
# => "hello" printed

setCurrentValue("goodbye") # => "goodbye" printed

有关详细信息,请查看本指南:https://meteor.hackpad.com/DRAFT-Understanding-Deps-aAXG6T9lkf6(请注意,Tracker最初在旧版Meteor中称为Deps)