【问题标题】:knockout.js - when do computed items recalculate dependencies?knockout.js - 计算项何时重新计算依赖项?
【发布时间】:2012-12-07 16:49:25
【问题描述】:

假设你有以下js:

  var vm = {
    objects: ko.observable([]),
    objectCount: ko.computed(function(){
      return vm && vm.objects().length;
    }),

    add: function() {
      var current = vm.objects();
      current.push({});      
      console.log('current is', current);
      vm.objects(current);
      console.log("should recalculate here", vm.objectCount());
    }
  };

还有下面的html:

  <ul data-bind="foreach: objects">
    <li>
      Object: <span data-bind="text: $index"></span>
    </li>
  </ul>
  <button data-bind="click: add">Add Object</button>
  <p>
    Total number of objects:
    <span data-bind="text: objectCount"></span>
  </p>

我的理解from reading the documentation 是因为在我添加一个对象后我调用了 objectCount(),它应该重新计算它的依赖关系。相反,它似乎甚至从未执行过该函数,只运行一次!

JSBin demonstrating a simplified version of my issue.

【问题讨论】:

    标签: knockout.js computed-observable


    【解决方案1】:

    在定义你的 viewModel 之后定义你的计算 - http://jsbin.com/welcome/58760/ - 这是因为计算的 observables 的工作方式(来自 ko docs)。

    1. 每当您声明一个计算的 observable 时,KO 立即调用 它的求值函数来获取它的初始值。
    2. 当您的评估功能运行时,KO 会记录任何 您的评估者读取的可观察的(或计算的可观察的) 的价值。
    3. 当您的评估员完成后,KO 会为每个 你接触过的 observables(或计算出的 observables)。
      订阅回调设置为使您的评估器再次运行,
      将整个过程循环回第 1 步(处理任何旧的
      不再适用的订阅)。
    4. KO 通知所有订阅者您计算的新值 可观察到。

    在 vm 对象中实例化 observable 时,其他属性还不存在。

    【讨论】:

    • 对,但是第 3 点暗示它会重新计算,不是吗?尽管仔细阅读它意味着该值已被记忆并且仅在订阅者更新时才更新(解释我的问题)。我确实想指出,尽管在您的示例中删除复选标记不起作用 - 因为这些也是可以观察到的,所以我不确定为什么会这样。
    • 但是当评估器完成时,您的 vm 对象上没有可观察对象(它们还不存在,因为 var 语句尚未完成)。 checked() 不起作用,因为您使用的是 value: binding 而不是 checked: 在复选框上,这是更新后的小提琴 - jsbin.com/welcome/58799 - 我还将对象更改为 observableArray,这样 ko 只会在你渲染新元素时推送它们,而不是重新渲染整个数组。我还建议将您的视图模型定义为函数并按照 Josh 的建议将它们实例化,但这并不能解释为什么它不起作用。
    【解决方案2】:

    这只是一个范围界定问题。如果您将脚本代码重构为如下所示:

    $(function(){
      var vm = function(){
        var self = this;
    
        self.objects = ko.observable([]);
        self.objectCount = ko.computed(function(){
          return self.objects().length;
        });
    
        self.add = function() {
          var current = self.objects();
          current.push({});      
          console.log('current is', current);
          self.objects(current);
          console.log("should recalculate here", self.objectCount());
        };
      };
    
      ko.applyBindings(new vm());
    });
    

    然后确定正确的变量范围,并且 Knockout 会正确计算依赖关系。正如guigouz 所说,最初调用ko.computed 时,vm 是未定义的,因此它无法设置任何更改处理程序。

    这里是the updated JSBin

    【讨论】:

      【解决方案3】:

      另一种方法是为ko.computed 使用deferEvaluation 选项。这将告诉 Knockout 等待计算计算的 observable 直到它第一次使用。到那时,vm 将被定义。

      objectCount: ko.computed(function(){
        return vm && vm.objects().length;
      }, null, { deferEvaluation: true }),
      

      【讨论】:

      • 哦,好的提示,不知道那个。尽管我很喜欢教程风格,但我真的“愿意”希望他们也有一些 api 文档。
      • ko.computed有一个简短的参考部分:knockoutjs.com/documentation/…
      猜你喜欢
      • 2022-01-15
      • 2013-01-14
      • 2012-08-27
      • 2012-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      相关资源
      最近更新 更多