How will Tracker.autorun choose its calculations?

Looking at Tracker.autorun it mostly works magically ... but I would like to know how it decides which variables go to form the dependency for the computation. It only selects "reactive" vars, for example the following:

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

      

If you change the value Session.set('foo')

, it will restart the calculation. whereas a simple change window.bar

does not trigger a restart. If I use the result of the subscription (not the collection) this also works, so I guess is reactive too.

Are there any guides for understanding this behavior a little better?

EDIT:

thanks for the comments below, which clarify that the computation can be inferred because the accessors are used for jet wars, so the meteorite can track fingerprints.

However, I need a little more clarity to understand when the var symbol is marked. for example, in this example below, the call subscribe

is out of bounds autorun

, but it puts the results into an array. This means that Tracker is not just about tracking calls (accessive var) of accessor methods, but also any variables referenced in a block, even if the calls to set these methods are outside the block 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

      

Perhaps I should add this as a new question ... related to this question .

+3


source to share


2 answers


I'm not an expert and don't read much about this, but I can try to explain it briefly.




All reactive variables have a property called dependency. For example, creating a new one ReactiveVar

creates a new dependency. See here .

To get a value from a reactive variable, you need to call a function. This "getter" instructs dependencies to remember that it has a dependency. For example, see here for ReactiveVar.get

.

To change the value for a reactive variable, you need to call the function. This "setter" notifies the dependency that something has changed, and signals that all functions that depend on the dependency should be repeated. For example, see here for ReactiveVar.set

.




Not difficult, right? Well it was just the easy part, all that's left now is building the infrastructure that makes it work :) This is harder and harder to explain.

Reactive variables do not respond by themselves; they must be evaluated in a reactive environment to be reactive. The reactive environment is created by calling Tracker.autorun

. See here .

When you call Tracker.autorun

, the function you passed to it will be executed in the new reactive environment, and all dependencies that the reactive variables notify with the method depend

will be tracked by the environment. When you call aDependency.depend

, this function will be executed and this adds the dependency to the list of environments by the dependencies it depends on.

When a reactive variable changes its value, this function will be executed. It tells the environment that one of the reactive variables it depends on has changed, and removes any dependencies in the environment. After that, all the function you passed to Tracker.autorun

will be rerun and new dependencies will be monitored.

Are you getting the big picture? This implementation is a little more complicated than what I explained, but I think this is how it works.

+4


source


Note that whenever you access a reactive variable it is through a function call like Session.get(...)

either collection.find(...).fetch()

, or Meteor.status()

. The function of the type Session.get

not only gets the value of the Session variable, but also registers the dependency on the current computation (the current computation is dynamically constrained, so it Session.get

knows that it was called from autorun).

Here's how you can implement your own reactive variable with 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

      



And this is how you could use it:

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

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

      

For more information, you can check out this tutorial: https://meteor.hackpad.com/DRAFT-Understanding-Deps-aAXG6T9lkf6 (note that Tracker was originally named Deps in older versions of Meteor)

+4


source







All Articles