Knockout订阅正在意外地进行评估

时间:2013-07-24 21:06:04

标签: knockout.js knockout-subscribe

我需要一个时间戳来更新值。由于我不会进入这里的原因,value是一个可写的计算指向valueInstance可观察的,因此它们基本上显示相同的数据。

如果我订阅了observable它按预期工作,只有在observable发生变化时才会触发。如果我订阅了计算它会立即触发导致错误的时间戳,即使observable仍未定义。怎么了?

http://jsfiddle.net/bNXhm/

更新:看起来只有在计算出的deferEvaluation: true

时才会发生这种情况

http://jsfiddle.net/bNXhm/1/

function VM(){
    var self = this;

    self.valueInstance = ko.observable();
    self.value = ko.computed({
        read: function () {
            return self.valueInstance();
        },
        write: function (value) {
            self.valueInstance(value);
        },
        deferEvaluation: true
    });

    self.timeStamp1 = ko.observable();
    self.value.subscribe(function (newValue) {
        self.timeStamp1(new Date());
    });

    self.timeStamp2 = ko.observable();
    self.valueInstance.subscribe(function (newValue) {
        self.timeStamp2(new Date());
    }); }

2 个答案:

答案 0 :(得分:1)

deferEvalaution计算出来时,在有人请求其值之前,不会对其进行评估。绑定时会发生这种情况。在评估时,它会通知任何订户。这可以解释为什么您的订阅被点击。

答案 1 :(得分:1)

创建observable时,除非将deferEvaluation设置为true,否则将对其进行评估。 当评估可观察(或计算)时,它总是通知它们订户。此时没有与之前的值进行比较(仅在值发生变化时才通知)。

“无用的通知检查”是在observable的setter中进行的。

因此,在您的代码中,当您在false时使用deferEvaluation时,会立即评估read函数并通知订阅者。但目前没有订阅者。这就是为什么没有设定时间跨度的原因。

当您使用deferEvaluation:true时,评估过程是applyBindings函数的延迟。此时您已经订阅了,这就是设置时间跨度的原因。

要解决您的问题,我会在您应该开始记录更改时创建一个存储变量。

function VM(){

    var self = this;
    self.logged  = false;


    self.valueInstance = ko.observable();
    self.value = ko.computed({
        read: function () {
            return self.valueInstance();
        },
        write: function (value) {
            self.valueInstance(value);
        },
        deferEvaluation: true
    });

    self.timeStamp1 = ko.observable();
    self.value.subscribe(function (newValue) {
        if(self.logged)
            self.timeStamp1(new Date());
    });

    self.timeStamp2 = ko.observable();
    self.valueInstance.subscribe(function (newValue) {
        if(self.logged)
             self.timeStamp2(new Date());
    });
}
var vm  = new VM();
ko.applyBindings(vm);
vm.logged = true;

我希望它有所帮助

See fiddle