Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how does Tracker.autorun pick out its computation?

Tags:

meteor

Looking at Tracker.autorun, this mostly works magically...but I'd like to know how it decides which variables are going to form the dependency for the computation. It picks out only "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 I change the value of Session.set('foo') this will cause the computation to run again. whereas just changing window.bar doesn't cause a rerun. If I use a subscribe result (not a collection) this also works, so that I guess is reactive too.

Are there any guides to understanding this behavior a bit better?

EDIT:

thanks for the comments below that clarify the computation is able to be inferred because accessors are used for reactive vars, so meteor can track deps.

However I need a bit more clarity to understand when a var is flagged. for instance in this example below, the subscribe call is outside the autorun, but it puts the results into an array. So that means that Tracker is not just tracking calls to (reactive var) accessor methods, but also any variables that are referenced within a block - even if the calls to setup those methods are outside the autorun() block.

  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

maybe i should add this as a new question... it's related to this question .

like image 792
dcsan Avatar asked Jan 09 '23 15:01

dcsan


1 Answers

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


All reactive variables have a thing called a dependency. For example, when one creates a new ReactiveVar, an new dependency is created. See here.

To retrieve the value from a reactive variable, one must call a function. In that "getter", the dependency is instructed to remember that it has a dependency. For example, see here for ReactiveVar.get.

To change the value for a reactive variable, one must call a function. In that "setter", the dependency is notified that something has changed, and that signals that all functions depending on the dependency must rerun. For example, see here for ReactiveVar.set.


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

Reactive variables aren't reactive by themselves; they must be evaluated in a reactive environment in order to be reactive. A 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 a new reactive environment, and all dependencies the reactive variables notifies of with the depend method will be tracked by the environment. When you call aDependency.depend, this function will be executed, and it kind of adds the dependency to the environments list over 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 invalidates all the dependencies in the environment. After this has happened, the entire function you passed to Tracker.autorun will be re-run, and the new dependencies will be tracked.

Do you get the big picture? It's implementation is a bit more complicated than I've explained, but I think that's kind of how it works.

like image 183
Peppe L-G Avatar answered Jan 21 '23 15:01

Peppe L-G