11
votes

KnockoutJS has the concept of computed observables, which are functions that depend on one or more observables. Knockout is able to determine the dependencies of a computed observable as described in the docs:

Whenever you declare a computed observable, KO immediately invokes its evaluator function to get its initial value. While your evaluator function is running, KO keeps a log of any observables (or computed observables) that your evaluator reads the value of.

Now, what I don't understand is, how this works if your computed observable contains conditional logic. If Knockout invokes the evaluator function, surely conditional logic might result in observables which the function depends on not being invoked?

I created this fiddle to test:

http://jsfiddle.net/bJK98/

var ViewModel = function(first, last) {
    this.firstName = ko.observable(first);
    this.lastName = ko.observable(last);
    this.condition = ko.observable(false);

    // at the point of evaluation of this computed observabled, 'condition'
    // will be false, yet the dependecy to both firstName and lastName is
    // identified
    this.fullName = ko.computed(function() {
        return this.condition() ? this.firstName() : this.lastName();
    }, this);
};

However, somehow Knockout correctly identified the dependency to both firstName and lastName.

Can anyone explain how?

2
Can't get the question, I believe computed observables determines own state in run time by evaluating all dependencies, so all looks clear and straightforward, sorry but can't get a main point of your questionsll
Good question. I always thought the approach they describe in the manual as you've quoted was pretty smart, but now that you point out this, I wonder if it's very smart and not just pretty smart... :DJani Hartikainen

2 Answers

13
votes

dependencies are tracked again each time that a dependentObservable is re-evaluated. So, if you have conditional logic, then the branch that is not hit will not contribute to the dependencies.

In your fiddle, if you edit the firstName, then the value is not updated until you toggle condition. At that point, lastName is no longer a dependency, so changes to it do not trigger the dependentObservable.

It is not really more complex than the original description. The basic thing to remember is that dependencies are recorded each time that it is re-evaluated.

1
votes

In knockout dependencies are tracked through it's single tracker variable ko.dependencyDetection.

  1. So whenever you declare a computed variable Knockout immediately invokes its evaluator function to get it's initial value and dependencies.
  2. So during this first call it will register it's dependencies on lastName and condition variables.
  3. Now whenever lastName changes it will update all it's dependent values.
  4. And whenever condition changes it will run again it's evaluator function and update all the dependencies. So it will add firstName as dependency and remove lastName.

So, this is how dependency tracking works in knockout.