如果依赖项在false branch语句中,则计算的停止会永久触发

时间:2016-03-16 12:56:17

标签: knockout.js knockout-3.0 computed-observable

我遇到了一个问题,即我的计算的observable在一系列依赖项更改后停止触发。最后我发现了一点:如果在最近的评估期间依赖关系在假分支语句中,那么即使条件在评估完成之前变为真,也不会触发计算。 以下是一个示例: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。我看到的一个令人遗憾的是,即使UI的相应部分是不可见的,也会进行调用。我试着用这种方式修复它:https://jsfiddle.net/bpr88bp3/1/。问题是,一旦标签被去激活,它就不能被激活,因为计算停止触发......

3 个答案:

答案 0 :(得分:3)

根据Knockout JS documentation

  

因此,Knockout不仅仅是第一次检测到依赖关系   评估者运行 - 每次都重新检测它们。

if(test !== 0){为false时,由于在计算重新计算期间未调用self.trigger(),Knockout不会订阅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--;
    });
  }();

答案 1 :(得分:2)

一般来说,这个想法是计算出的observable的所有依赖关系也应该是可观察的。在您的情况下,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

但是这引入了另一个问题,因为您现在正在更改计算的observable中的一个依赖项。通过逻辑地改变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); } }); }(); ,应该递归地计算计算值。如果计算是同步的,Knockout会阻止这种情况,但这不是一个真正的功能,它可能会在以后引起问题。

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

apnsclient

答案 2 :(得分:2)

在阅读了您的问题的更新并查看更新的示例代码后,我想出了一个真正的解决方案。这使用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/