如果依赖项在错误的分支语句中,Computed 将永远停止触发

Computed stops triggering forever if dependency is inside of false branch statement

我遇到了一个问题,即我的计算可观察对象在某些依赖项更改序列后停止触发。最后我发现了一点:如果在最近的评估期间依赖项在错误的分支语句中,计算将不会在下一次被触发即使在评估完成之前条件变为真。 这是一个示例:https://jsfiddle.net/sgs218w0/1/

var viewModel = new function(){
  var self = this;

  self.trigger = ko.observable(true);
  self.fire = function(){
    self.trigger(! self.trigger());
  };

  self.content = function(){
    var test = 3;
    return ko.computed(function(){
      alert("triggered!");
      if(test !== 0){
        console.log(self.trigger());
        alert(test);
      }
      test--;
    });
  }();
};

ko.applyBindings(viewModel);

这是错误还是功能?您知道此问题的任何解决方法吗? 我似乎在优化,但对我来说它看起来很激进且不正确。 (编辑:我改变了主意。这是合理的,但有时会导致一些问题。我认为淘汰赛应该有解决这个问题的选项)

P.S。如果您需要,我可以发布更详细的真实代码示例以使问题更具体。但是真正的代码点是一样的。

更新 好吧,我不得不懒得提供更详细的例子来说明我想要实现的目标。我喜欢计算的想法,它会自动进行 ajax 调用。描述 here. One disadventure I see is that call will be made even if corresponding part of UI is invisible. I tried to fix it this way: https://jsfiddle.net/bpr88bp3/1/。问题是,一旦选项卡被取消激活,它就不能再被激活,因为计算停止触发...

根据淘汰赛JS documentation:

So, Knockout doesn’t just detect dependencies the first time the evaluator runs - it redetects them every time.

if(test !== 0){ 为 false 时,Knockout 不会订阅 self.trigger(),因为 self.trigger() 在计算重新计算期间未被调用。 如果没有订阅 self.trigger(),则不会根据进一步的 self.trigger() 更改重新计算计算值。

恕我直言,解决方法是在任何情况下都获得 self.trigger() (updated fiddle):

self.content = function(){
    var test = 3;
    return ko.computed(function(){
      var triggerValue = self.trigger();
      alert("triggered!");
      if(test !== 0){
        console.log(triggerValue);
        alert(test);
      }
      test--;
    });
  }();

总的来说,这个想法是计算的可观察对象的所有依赖项也应该是可观察的。在您的情况下, test 不是可观察的;如果你让它可观察,你的代码应该按预期工作:

self.content = function(){
  var test = ko.obseravble(3);
  return ko.computed(function(){
    alert("triggered!");
    if(test() !== 0){
      console.log(self.trigger());
      alert(test);
    }
    test(test()-1);
  });
}();

但这引入了另一个问题,因为您现在正在更改计算的可观察对象中的一个依赖项。通过更改 test,从逻辑上讲,应该递归地计算计算值。如果计算是同步的,Knockout 会阻止这种情况,但这并不是一个真正的特性,它可能会在以后引起问题。

以下是我认为可以正确隔离组件含义的更好解决方案:

self.content = function(){
  var respondToTriggerChange = ko.obseravble(3);
  self.trigger.subscribe(function () {
    respondToTriggerChange(respondToTriggerChange()-1);
  });
  return ko.computed(function(){
    alert("triggered!");
    if(respondToTriggerChange()){
      console.log(self.trigger());
      alert(test);
    }
  });
}();

阅读您问题的更新并查看更新后的示例代码后,我想出了一个真正的解决方案。这使用 pureComputed 进行更新,利用纯计算可以通过订阅和处理订阅来激活和停用这一事实。这是重要的代码:

updateComputed = ko.pureComputed(function () {
    updateTrigger();
    result(evaluator.call(owner));
});
ko.computed(function () {
    var isActive = result.active();
    if (isActive && !updateSubscription) {
        updateSubscription = updateComputed.subscribe(function () {}); 
    } else if (updateSubscription && !isActive) {
        updateSubscription.dispose();
        updateSubscription = undefined;
    }
});

https://jsfiddle.net/mbest/bpr88bp3/2/