有没有办法告诉knockout等到重新计算计算值,直到定义视图模型? [英] Is there a way to tell knockout to wait to recalculate computed values until after the view model is defined?

查看:60
本文介绍了有没有办法告诉knockout等到重新计算计算值,直到定义视图模型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a complex view model which is a couple hundred lines of javascript code with a good amount of observable properties, computed observable properties, writable computed observable properties and functions. So managing this is quite a bit of a challenge.

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

An annoying problem that I've had to deal with is that computed observables are calculated immediately right when you define it. So using variables that haven't been defined yet in the view model at the point of defining the observable lead to errors stating that the variable hasn't been defined. It is... just later in the file.

这是一个人为的例子:

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

使用 ViewModel1 将工作没有问题。在定义 fullName 时, firstName lastName 是定义所以它按预期工作。使用 ViewModel2 将无效。计算函数中会出现一个错误,说明 firstName 未定义。

Using ViewModel1 will work with no problems. At the point fullName is defined, firstName and lastName is defined so it works as expected. Using ViewModel2 will not work. There would be an Error in the computed function stating firstName is not defined.

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

What I've been doing until now was to ensure that all computed observables are defined after all dependent variables have been defined. The problem with this is that in doing so, things are defined in seemingly random places when I would rather keep related variables defined close together.

我有一个很好的解决方案想出来的是将初始化可观察集定义为 true ,并使所有计算的observables测试它是否仍在初始化并计算并返回值。这样,将不会尝试访问当前未定义的变量。

One nice solution that I've come up with is to define an "initializing" observable set to true and make all computed observables test if it's still initializing and calculate and return the value when it isn't. That way, the attempts to access the currently undefined variable will not be made.

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

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

But this won't be very practical in my case however. I have many computed observables, so doing this in all of them will make it very bloated, remember I have a lot of these. Throttling it doesn't seem to make a difference.

在尝试计算计算的可观察量的值之前,有没有办法告诉淘汰赛等待?或者有没有更好的方法来构建我的代码来处理这个问题?

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

I could probably make some helper functions to manage the initialization logic, but I'd still have to alter all of the computed observable definitions. I suppose I can monkey patch knockout to add this initializing logic as I'm not aware knockout has such options which I might just do. I've looked at the source for computed observables before but I don't know if there's already a setting elsewhere.

jsfiddle demo

推荐答案

计算的observables接受 deferEvaluation 阻止初始评估发生的选项,直到实际尝试检索计算值的值为止。

Computed observables accept a deferEvaluation option that prevents the initial evaluation from happening until something actually tries to retrieve the computed's value.

您可以将其定义为:

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

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

Just for completeness, you could also specify it like:

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

或者你可以把它换成:

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

这篇关于有没有办法告诉knockout等到重新计算计算值,直到定义视图模型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆