有没有办法告诉knockout等到重新计算计算值,直到定义视图模型?

Jef*_*ado 24 javascript knockout.js

我有一个复杂的视图模型,它是几百行的javascript代码,具有大量的可观察属性,计算的可观察属性,可写的计算可观察属性和函数.所以管理这个是一个相当大的挑战.

我必须处理的一个恼人的问题是,在您定义计算的observable时会立即计算出它.因此,在定义可观察对象时,使用尚未在视图模型中定义的变量会导致错误,表明该变量尚未定义.它......就在文件的后面.

这是一个人为的例子:

function ViewModel1?(args) {
    var self = this;

    self.firstName = ko.observable(args.firstName);
    self.lastName = ko.observable(args.lastName);
    self.fullName = ko.computed(function () {
        return self.firstName() + ' ' + self.lastName();
    });
}

function ViewModel2?(args) {
    var self = this;

    self.fullName = ko.computed(function () {
        // uh oh, where's firstName?
        return self.firstName() + ' ' + self.lastName();
    });
    self.firstName = ko.observable(args.firstName);
    self.lastName = ko.observable(args.lastName);
}
Run Code Online (Sandbox Code Playgroud)

使用ViewModel1将毫无问题地工作.在fullName定义点,firstNamelastName定义,以便它按预期工作.使用ViewModel2不起作用.计算出的函数中会出现一个错误,说明firstName未定义.

到目前为止我一直在做的是确保在定义了所有因变量之后定义所有计算的可观察量.这样做的问题在于,当我宁愿将相关变量保持在一起时,事情在看似随机的地方被定义.

我提出的一个很好的解决方案是定义一个"初始化"可观察集true,并使所有计算的可观察量测试如果它仍在初始化并计算并返回该值而不是.这样,将不会尝试访问当前未定义的变量.

function ViewModel3(args) {
    var self = this;
    var initializing = ko.observable(true);

    self.fullName = ko.computed(function () {
        if (!initializing()) {
            return self.firstName() + ' ' + self.lastName();
        }
    });
    self.firstName = ko.observable(args.firstName);
    self.lastName = ko.observable(args.lastName);

    initializing(false);
}
Run Code Online (Sandbox Code Playgroud)

但是,在我的情况下,这不是很实用.我有很多计算的observable,所以在所有这些中做这个会使它非常臃肿,记住我有很多这些.限制它似乎没有什么区别.

有没有办法告诉knockout在尝试计算计算的observables的值之前等待?或者,有没有更好的方法来构建我的代码来处理这个?

我可能会做一些辅助函数来管理初始化逻辑,但我仍然需要改变所有计算的可观察定义.我想我可以通过猴子补丁淘汰来添加这个初始化逻辑,因为我不知道淘汰赛有这样的选择,我可能会这样做.之前我已经查看了计算可观察量的来源,但我不知道其他地方是否已有设置.

jsfiddle演示

RP *_*yer 40

计算的observable接受一个deferEvaluation选项,阻止初始评估发生,直到实际尝试检索计算的值.

您可以将其定义为:

self.fullName = ko.computed({
   read: function() {
       return self.firstName() + " " + self.lastName();
   },
   deferEvaluation: true
});
Run Code Online (Sandbox Code Playgroud)

为了完整起见,您还可以指定它:

this.fullName = ko.computed(function() {
       return this.firstName() + " " + this.lastName();
 }, this, { deferEvaluation: true });
Run Code Online (Sandbox Code Playgroud)

或者你可以包装它:

ko.deferredComputed = function(evaluatorOrOptions, target, options) {
   options = options || {};

   if (typeof evaluatorOrOptions == "object") {
       evaluatorOrOptions.deferEvaluation = true;   
   } else {
       options.deferEvaluation = true;
   }

   return ko.computed(evaluatorOrOptions, target, options);
};
Run Code Online (Sandbox Code Playgroud)

  • 我也在我的代码中使用`deferEvaluation`.在[文档](http://knockoutjs.com/documentation/computedObservables.html)中获取有关它的信息会很好. (2认同)
  • @DirkBoer - 不,使用它的缺点,只要你不使用计算简单地对一个或多个observables的变化作出反应并做某事(相对于计算的绑定).不是默认值,主要用于向后兼容. (2认同)