初学knockoutjs记录6——Computed observables依赖监控(3 How dependency tracking works 依赖跟踪是如何工作的)

How dependency tracking works 依赖跟踪是如何工作的

  初学者可以不关心它,但是高级开发会想要知道我们为什么能保证所有的关于KO的请求都自动的跟踪依赖并正确的更新UI...

  事实上很简单也很好理解,跟踪的过程是这样的:

    1. 任何时候你声明了一个计算监控属性,KO将立刻调用它的计算函数以获取它的初始值。

    2. 当这个计算函数执行的时候,KO会在这个计算函数读取的任何一个监控属性(包括其他的计算监控属性)上设置订阅,订阅的回调会被设置为触发这个计算函数的再次运行,循环整个过程回到第一步(处理掉任何不在需要的旧的订阅)。

    3. KO通知所有有关你的计算监控属性的订阅。

  因此,KO不只监控你的计算函数首次运行时的依赖,它监控每一次执行。这也意味着,例如这个依赖可以是动态变化的:依赖A能够判断这个计算监控属性是否也依赖B或者C,然后,它只会在A或者当前的选择B或C其中一个变化时才会重新计算,你不需要声明所有的以依赖,它们会在代码运行时决定。

  另一个技巧是实现计算监控属性的绑定声明很简单,所以,当一个绑定读取一个监控属性的值时,这个绑定将依赖这个监控属性,也就是说如果这个依赖变化了,就会引起绑定的重新计算。

  纯计算监控属性的工作机制稍有不同,更多细节请参见 pure computed observables.

Controlling dependencies using peek 使用 peek 控制依赖

  KO的自动依赖跟踪通常情况下就是你想要的,但是有时你可能希望显示的控制你的计算监控属性的更新,特别是当你的计算监控属性需要执行一些特殊行为,例如调用Ajax请求。peek函数可以使你在不触发依赖的情况下访问监控属性或计算监控属性。

  在下边的例子中,一个计算监控属性用于使用Ajax重新加载依赖另外两个监控属性的叫做 currentPageData的监控属性,任何时候当 pageIndex 变化的时候,这个计算监控属性都将更新,但它忽略了 selectdItem 的改变,因为它是使用的peek进行访问的。在这个场景中,用户通常只是想要在一个新的集合加载的时候使用 selectedItem的当前值用来跟踪。

ko.computed(function(){
    var params = {
          page: this.pageIndex(),
          selected: this.selectedItem.peek()
    };
    $.getJSON('/some/Json/Service', params, this.currentPageData);
}, this);

注意:如果你仅仅只是想要限制计算监控属性频繁的更新,请参见 rateLimit extender.
Ignoring dependencies within a computed 在计算中忽略依赖

  ko.ignoreDependencies 在这样的场景中很有用:当你想要在计算中执行代码但又不想触发计算依赖时。当你在自定义绑定中使用代码访问监控属性,但是又不想触发绑定的依赖监控变化的时候它很有用。

ko.ignoreDependencies( callback, callbackTarget, callbackArgs);

  例子:

ko.bindingHandler.myBinding = {
    update: funciton (element, valueAccessor, allBindingsAccessor, viewModel, bindingComtext) {
        var options = ko.unwrap(valueAccessor());
        var value = ko.unwrap(options.value);
        var afterUpdateHandler = options.afterUpdate;

        if (typeof afterUpdateHandler === "function") {
            ko.ignoreDependencies(afterUpdateHandler, viewModel, [value, color]);
        }

        $(element).somPlugin("value", value);
    }
}

注意: Why circular dependencies aren't meaningful 为什么循环依赖没有意义
  计算监控属性假定映射一组监控属性输入到一个单一监控属性输出,因此,当你的依赖包含循环的时候它将没有意义。循环不同于递归,它类似于表格上两个单元格互相计算,它将导致无限循环。

  那么,在你的依赖中出现了循环的时候ko是怎样处理的呢?它通过执行如下的规则来避免无限循环: ko 将不会再次执行一个计算监控属性的计算函数,如果它已经被执行过。 这很可能会影响到你的代码。如下相关的两个场景:当两个计算监控属性互相依赖的时候(很有可能其中一个或两个都应用了 deferEvaluation 选项), 或者当一个计算监控属性写入另一个它依赖(通过依赖链直接或间接)的监控属性。如果你确实需要像这种模式下使用并且要完全避免循环依赖,你可以像上边的例子中那样使用peek函数。