Knockout计算与订阅,时间问题

时间:2013-11-20 07:32:33

标签: javascript knockout.js

刚刚发现,KnockoutJS订阅函数在依赖计算机之前进行评估,需要有人可以提交,因为我无法在文档或论坛中找到关于Knockouts时序的任何内容。

这意味着:如果我有这样的模型......

var itemModel = function (i) {
    var self = this;

    self.Id = ko.observable(i.Id);
    self.Title = ko.observable(i.Title);
    self.State = ko.observable(i.State);

};

var appModel = function () {
   var self = this;

   self.Items = ko.observableArray() // <-- some code initializes an Array of itemModels here
   self.indexOfSelectedItem = ko.observable();

   self.selectedItem = ko.computed(function () {
       if (self.indexOfSelectedItem() === undefined) {
            return null;
       }
       return self.Items()[self.indexOfSelectedItem()];
   });
};

我想跟踪一个带有可观察索引字段的所选数组项,我订阅这个索引字段就像这样......

appModel.indexOfSelectedItem.subscribe(function () {
    // Do something with appModel.selectedItem()
    alert(ko.toJSON(appModel.selectedItem()));
}

...在使用新索引值重新评估计算之前评估订阅函数,因此我将获得与最后选择的索引对应的selectedItem(),而不是实际选择的索引。

两个问题:

  • 是吗?
  • 那么为什么我应该使用ko.computed()如果一个简单的函数每次调用它时都会获取当前所选项目,而ko.computed会在任何时候进行评估,而且我不再需要它了?

1 个答案:

答案 0 :(得分:3)

默认情况下,Knockout中的所有计算都是以急切的方式评估,而不是懒惰(即,首次访问时)。

只要一个依赖项发生更改,就会通知所有订阅,并重新评估所有连接的计算。您可以通过在计算的observable中指定the deferEvaluation option将该行为更改为“lazy”,但不能对订阅执行此操作。

Hoewever,我认为没有必要依赖所选项目的索引。事实上,这甚至是糟糕的设计,因为你不是真正在索引的数值中,而是在它所代表的项目中。

您可以通过创建可写的计算observable来反转依赖关系,该observable为您提供当前所选项目的索引(用于显示目的)并允许更改它(为方便起见)。

function AppModel() {
    var self = this;

    self.Items = ko.observableArray();
    self.selectedItem = ko.observable();

    self.indexOfSelectedItem = ko.computed({
        read: function () {
            var i,
                allItems = self.Items(),
                selectedItem = self.selectedItem();

            for (i = 0; i < allItems.length; i++) {
                if (allItems[i] === selectedItem) {
                    return i;
                }
            }
            return -1;
        },
        write: function (i) {
            var allItems = self.Items();

            self.selectedItem(allItems[i]);
        }
    });
}

Knockout倾向于存储/处理实际值而不仅仅是索引值,因此对视图进行必要的更改可能并不困难。只需将以前写入indexOfSelectedItem的所有内容直接写入selectedItem即可。 selectedItem的依赖关系将继​​续正常运作。

在精心设计的Knockout应用程序中,您很少需要处理数组项的索引。一旦一切正常,我建议删除计算的write部分。

请参阅:http://jsfiddle.net/4hLLn/