Knockout v3.4.0 中文版教程-7-计算监控-依赖跟踪如何工作

3.依赖跟踪如何工作

初学者不需要知道这一点,但更高级的开发人员将想知道为我们怎么实现KO自动跟踪依赖性和自动更新UI的正确部分...

它其实相当简单优雅,跟踪算法如下:

  1. 当你定义一个计算监控,KO立即调用其求值函数来获得初始值。
  2. 当求值函数运行,KO添加一个订阅到任何求值函数可读取的监控对象上(包括其他计算监控对象)。订阅的回调函数会触发求值函数重新运行,整个过程循环回到步骤1(释放任何不再使用的旧订阅)。
  3. KO通知任何订阅者获取你的计算监控的新值。

因此,KO不只是在第一次求值程序运行的时候检测依赖关系,每次都会重新检测。这意味着,例如,依赖关系可以动态变化:依赖A可以决定是否计算监控也取决于B或C,那么,它只会重新求值,无论是A或你目前选择的B或C发生变化。您不必声明依赖项:它们在代码执行的运行时中确定。

另一个诀窍是声明性绑定可以看做是计算监控的简单实现。因此,如果一个绑定读取一个监控的值,绑定会依赖于监控,这将导致如果监控发生变化,绑定会重新求值。

1. 使用peek控制依赖

KO的自动依赖跟踪通常如你想要的那样工作。但你可能有时需要确定哪一个监控将导致重新对计算监控求值,特别是如果计算监控执行一些操作,如发送一个Ajax请求。peek函数可以让你访问一个监控或计算监控的值,而不会创建一个依赖。

在下面的例子里,一个计算监控用来重载一个叫做currentPageData的监控对象的值,该计算监控使用Ajax和来自其他两个监控属性的数据进行请求。每当pageIndex的值发生改变时,计算监控会重新求值,但是会忽略selectedItem的改变,因为是使用peek进行访问的。在这种情况下,用户可能想要使用selectedItem当前的值仅用于跟踪当新的数据集加载的时候。

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

注意:如果你想阻止计算监控频繁刷新,请使用频率限制扩展器。

2. 忽略计算中的依赖关系

ko.ignoreDependencies函数适用于如下场景,在你想执行一个计算代码,而计算监控不会重新求值。这在自定义绑定的情况下特别有用,当你想调用的代码可能会访问监控对象,但是你不想再触发基于这些监控对象的值更新。

ko.ignoreDependencies( callback, callbackTarget, callbackArgs );

例如:

ko.bindingHandlers.myBinding = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var options = ko.unwrap(valueAccessor());
        var value = ko.unwrap(options.value);
        var afterUpdateHandler = options.afterUpdate;
 
        // the developer supplied a function to call when this binding updates, but
        // we don't really want to track any dependencies that would re-trigger this binding
        if (typeof afterUpdateHandler === "function") {
            ko.ignoreDependencies(afterUpdateHandler, viewModel, [value, color]);
        }
 
        $(element).somePlugin("value", value);
    }
}

注意:为什么循环依赖是没有意义的
计算监控被用于映射一组监控对象的输入值进行计算,返回值作为一个简单监控对象的输出。因此,在你的依赖链中循环依赖是没有意义的。循环依赖不同于递归;它类似于两个电子表格单元互相计算对方的值。这会导致一个死循环。

那么,如果你在你的依赖关系图中有一个循环依赖,KO会做什么?它通过执行以下规则避免了无限循环:KO不会在一个计算监控已经在求值的情况下重新求值。这个不可能影响到你的代码。它跟两种情况有关联:当两个计算监控互相依赖(可能有人个使用deferevaluation选项),或者当一个计算监控把值写入另一个有依赖的监控对象(无论是直接依赖或通过依赖链)。如果你想要使用其中某个方式,而且想完全避免循环依赖,你可以使用如上所述的peek函数。

原文地址:https://www.cnblogs.com/DHclly/p/6291311.html