【问题标题】:Knockout: Computed Observable In Constructor Ignoring Changes To Instance淘汰赛:构造函数中的计算 Observable 忽略对实例的更改
【发布时间】:2013-07-15 05:10:38
【问题描述】:

我有一个由构造函数创建的视图模型,具有一堆可观察的属性和一堆普通的旧属性。一旦我实例化它,如果我在实例上设置一个值,对该值的更改不会反映在计算的 observable 中。

这是我正在查看的内容的精简版:

function ViewModel(active) {
    var self = this;
    self.active = active;

    self.getClasses = ko.computed(function () {
        return this.active ? "yup" : "nope";
    }, self);
}

var vm = new ViewModel(false);
vm.active = true;

alert(vm.getClasses()); //returns "nope" :/

如果我触摸它所依赖的可观察对象,这个计算的可观察对象将重新评估,但直接调用它会导致使用旧值 active 进行评估。

ko.computed 是否会创建一个忽略父项更新的新闭包?将普通值与可观察值混合是不明智的吗? (我实际上遇到的计算问题依赖于可观察对象和其他属性,但我不希望其他属性在运行时发生变化。这实际上只是我现在的单元测试中的一个问题。)

我当然可以将 active 设为 observable,但我想知道是否有其他方法可以做到这一点。

【问题讨论】:

  • 计算值只有在计算函数中的可观察属性改变时才会改变。如果没有可观察到的变化,那么计算将不会被重新评估......所以你需要制作self.active = ko.observable(active); 或者不要在这里使用计算,而是使用常规函数:self.getClasses = function () { return self.active ? "yup" : "nope"; }; 进一步阅读:knockoutjs.com/documentation/computedObservables.html 如何依赖跟踪作品部分
  • 再一次,我知道激活一个 observable 将导致计算出的 observable 更新。问题是我希望它在我 invoke 时更新,而不仅仅是在依赖项更改时。
  • 这不是ko.computed 的工作方式。评估器函数仅在最初且仅在依赖的可观察对象发生更改时才被调用。您不能告诉计算更新其值。所以不要在这里使用计算。
  • 为什么不将你的 getClasses 重写为一个普通函数呢?然后,您将获得活动的最新值。如果你不打算让它依赖于其他可观察对象,那么让它成为淘汰计算函数有什么意义?
  • @Tombala 这是一个简化的例子。实际上,我有一个计算的 observable,它从几个属性构建一个值,其中一些是可观察的。我试图最小化所涉及的可观察对象的数量,使它们仅用于我的 UI 需要做出反应的事情。它并不像我希望的那样顺利。 :)

标签: knockout.js


【解决方案1】:

Josh,内部的 ko.computed 会立即执行您的计算函数并存储结果,直到某些操作需要它重新计算自身(如订阅的可观察更改)。这种内部缓存可能会提供巨大的性能提升;如果订阅的值没有更改,则无需重新运行计算,因为结果应该相同。

这就是为什么将计算所依赖的任何值都创建为可观察值很重要的原因。

目前无法强制计算按需重新计算,因为这通常表明您的架构存在问题。如果您需要一个按需计算但不依赖于任何可观察值的值,那么常规函数将是实现该目标的最佳方法。

self.getClasses = function () {
      return self.active() ? "yup" : "nope";
  };

您可以绑定您的 UI 以显示常规函数的结果,就像显示计算结果一样,但您需要在绑定表达式中添加括号。请记住,这只会在绑定时显示函数的结果。如果您的计算发生变化,UI 将不会保持最新;为此,您需要一个 ko.computed。

<!-- this will only show the value at bind-time and never be updated -->
<div data-bind="text: getClasses()"></div>

如您所见,这不是很有用。总的来说,更多的 observables 对你的应用程序性能的影响不会超过几微秒。我的建议是推迟优化你的代码,直到你发现问题。与使您的代码更易于编写的一些可观察对象相比,您的用户更有可能看到循环评估或大型 AJAX 负载变慢。

我希望这会有所帮助!

【讨论】:

    【解决方案2】:

    您是否尝试过像这样设置可观察值:

    function ViewModel(active) {
      var self = this;
    
      self.active = ko.observable(active);
    
      self.getClasses = ko.computed(function () {
          return this.active() ? "yup" : "nope";
      }, self);
    }
    
    var vm = new ViewModel(false);
    vm.active(true);
    

    所以将 observable 设置为一个函数(括号中的值),而不是一个属性。并确保 active 被定义为可观察对象。

    【讨论】:

      【解决方案3】:

      如果您希望通知此变量的更改(并在计算中评估),则 Active 必须是可观察的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-02
        • 1970-01-01
        • 2017-03-05
        • 2013-04-10
        • 2016-07-21
        • 2020-05-30
        • 2013-03-22
        • 1970-01-01
        相关资源
        最近更新 更多