3

我遇到了一个问题,即我的计算出的 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);

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

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

更新 好吧,我必须不那么懒惰地提供更详细的示例来说明我想要实现的目标。我喜欢自动进行 ajax 调用的计算的想法。描述在这里。我看到的一个缺点是即使 UI 的相应部分不可见,也会进行调用。我试图以这种方式修复它:https ://jsfiddle.net/bpr88bp3/1/ 。问题是一旦选项卡被取消激活它就不能再被激活,因为计算停止触发......

4

3 回答 3

3

根据 Knockout JS 文档

因此,Knockout 不仅会在评估程序第一次运行时检测依赖关系 - 它每次都会重新检测它们。

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

self.trigger()恕我直言,解决方法是无论如何都要获得(更新的小提琴):

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--;
    });
  }();
于 2016-03-16T13:46:08.580 回答
2

一般来说,这个想法是计算的可观察对象的所有依赖项也应该是可观察对象。在您的情况下,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);
  });
}();

但这引入了另一个问题,因为您现在正在更改计算的 observable 中的一个依赖项。通过改变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);
    }
  });
}();
于 2016-03-16T21:41:55.970 回答
2

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

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/

于 2016-03-22T02:17:33.977 回答