7

我正在尝试为我的所有视图模型创建一个基类,例如,我可以检查 root-vm 上的“isDirty”并让它检查整个 vm 树(同时避免循环依赖)。

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

我的问题是:

在所有计算属性上使用 deferEvaluation 有什么缺点吗?为什么默认情况下这种行为不正确?我什么时候需要将其设置为 false?

我可以更好地执行 isDirty-property 吗?关于改进它或以其他方式做的任何建议?

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

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

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 });
}

注意:刚刚注意到如果我有另一个依赖于 isDirty 的计算属性,此代码将失败。这是意料之中的,但也是不幸的。如果我可以在对象创建后延迟并强制所有订阅,那就太好了。

4

2 回答 2

3

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

使用 时deferEvaluation,不会立即执行 a 的依赖关系检测ko.computed,而是在每次请求值时执行。

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

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


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

如果您的主要问题在于脏标志跟踪,您可以在基本 VM 中设置 beginInit() 和 endInit() 方法,并设置在 endInit() 内计算的 isDirty。您可能不需要 beginInit(),但它为一致性提供了一个很好的钩子,以后可能会有用。

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

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

于 2013-05-01T17:38:55.333 回答
2

如果您computed确实是一个计算,那么将评估推迟到有人真正需要该值之前通常没有害处。

在某些情况下,您computed实际执行某些操作是作为获取价值的副产品或作为其唯一目的,那么推迟评估可能不是正确的选择。在某些情况下,acomputed可以用作订阅多个可观察对象并在其中任何一个发生更改时执行操作的一种方式,而不是简单地返回一个值。

在创建整个对象之前,除了推迟评估并稍后访问它之外,没有其他方法可以禁用初始化,除非您要执行类似在setTimeout. 但是,如果其他代码期望它存在,这可能会导致错误。

于 2013-05-01T17:39:05.797 回答