推迟对Knockout中所有计算属性的评估?

And*_*ita 7 knockout.js

我试图为我的所有视图模型创建一个基类,所以我可以检查root-vm上的"isDirty"并检查整个vms树(同时避免循环依赖).

执行此操作时,我意识到ko-properties的顺序非常重要,因为计算属性根据创建属性时存在的其他属性来设置其订阅.因此,如果我将一个像下面的那样的isDirty-computed放在一个基类中,它总是会在它所依赖的属性之前进行初始化.无论如何,为了缩短它,我注意到我可以使用deferEvaluation来解决这个问题.

我的问题是:

在所有计算属性上使用deferEvaluation是否有任何缺点?为什么默认情况下这种行为是正确的?我什么时候需要它设置为假?

我可以这样做是否更好?有关改进或以其他方式进行的任何建议吗?

或者,有没有办法显式禁用计算属性的初始化,直到创建具有其所有属性的整个对象,然后以某种方式运行它.我的意思是对我来说唯一的问题是订阅是在所有属性到位之前设置的.

注意:我正在使用KO Lite Tools进行脏跟踪

function ViewModel() {
    var self = this;
    self.isDirty = ko.computed(function () {
        for (var p in self) {
            if (self[p].isDirty) {
                if (self[p].isDirty()) return true;
            }
            else if (self[p].subscribe && self[p].push) { // assuming ko.observableArray
                for (var i = 0, j = self[p]().length; i < j; i++) {
                    if (self[p]()[i].isDirty) {
                        if (self[p]()[i].isDirty()) return true;
                    }
                }
            }
        }
        return false;
    }, this, { deferEvaluation: true });
}
Run Code Online (Sandbox Code Playgroud)

注意:注意,如果我有另一个依赖于isDirty的计算属性,则此代码将失败.这有点令人期待,但也很不幸.如果我可以在创建对象后延迟并强制所有订阅,那将是很棒的.

Jos*_*iel 3

正如您所发现的,通常情况下,ko.computed在首次创建计算时会计算 a 并检测依赖关系。

使用 时,不会立即执行 deferEvaluationa 的依赖性检测,而是在每次请求该值时执行。ko.computed

这提供了动态改变依赖关系的强大机制,但确实导致开销增加。

Ryan在本页对此进行了一些讨论(向下滚动到第 3 节 - 计算可观察量的基本规则):


是否可以构建您的代码,以便在创建其他属性 之后ko.computed定义这些值?

如果您的主要问题在于脏标志跟踪,您可以在基础虚拟机中设置 beginInit() 和 endInit() 方法,并设置在 endInit() 内计算的 isDirty。您可能需要也可能不需要 beginInit(),但它提供了一个很好的挂钩来保持一致性,并且以后可能会很有用。

当然,派生的 VM 需要在设置其可观察量之前和之后调用基本 init 方法。我不确定您当前创建派生虚拟机的策略是什么 - 我通常使用工厂来提供原型继承,并且我对初始化时间有这种控制。

beginInit() 和 endInit() 的一个更简单的替代方法是,在定义所有属性的派生类中简单地提供 initProperties() 函数,并从基础 VM 调用该方法,然后设置 isDirty 计算。