Search code examples
javascriptknockout.jscomputed-observable

How Knockout computed observable register to the relevant observables?


When we declare a computed observable in Knockout, all we have to do is to pass a function that will update this computed whenever one of the observables this function contains gets updated.

Example, from the Knockout documentation:

function AppViewModel() {
    this.firstName = ko.observable('Bob');
    this.lastName = ko.observable('Smith');

    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, this);
}

My question is simple, but I didn't find any information on that: how does a computed know which observables are contained in the passed function ? Does it execute some reflection like action to discover them during its initialization ?

I'm not a JS guru so maybe I'm missing something obvious, but if someone can point a piece of information...


Solution

  • The How dependency tracking works page describes at a high level what happens when a dependent (computed) observable is evaluated. However it doesn't go in depth how it is actually achieved. It's actually quite interesting.

    First of all, observables and dependent observables. Conceptually, these are just simple functions that hold a value. Observables will hold on to a value you give it and will return it to you if you call it. Dependent observables will update itself if any of the other observables or dependent observables it finds in its evaluator function is updated.

    But how does the dependent observable actually know about these observables and dependent observables in the evaluator?

    When reading the value of an observable or dependent observable, you're actually doing a little bit more than just retrieving the value. Behind the scenes, when getting the value, you're also registering a dependency on the current dependency detection frame. The frame is the mechanism used to keep track of what observables and dependent observables were called since the frame was created.

    The frame is created when dependency detection is enabled, which is usually when a dependent observable value function is evaluated. These frames can be nested of course when dependent observables are dependent on other observables and those are nested. The frame is removed when the evaluator function completes.

    And that's the gist of it. Look at the debug source if you really want to get into the details.