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

心已入冬 提交于 2019-12-04 14:58:24

After reading the update to your question and looking through the updated example code, I've come up with a real solution. This uses a pureComputed to do the update, taking advantage of the fact that a pure computed can be activated and deactivated by subscribing to it and disposing the subscription. Here is the important code:

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/

TSV

According to the Knockout JS documentation:

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

When if(test !== 0){ is false, Knockout does not subscribe to self.trigger() due to self.trigger() not being called during computed recalculation. With no subscription to the self.trigger(), there is no recalculation of the computed on further self.trigger() changes.

IMHO the workaround is to get self.trigger() in any case (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--;
    });
  }();

The idea, in general, is that all dependencies of a computed observable should also be observables. In your case, test isn't an observable; if you make it observable, your code should work as expected:

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

But this introduces another problem because you're now changing one of the dependencies within your computed observable. By changing test, logically, the computed should be evaluated recursively. If the computed is synchronous, Knockout prevents this, but this is not really a feature, and it could cause problems later.

Here's what I think is a better solution that properly isolates the meanings of the components:

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);
    }
  });
}();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!