Durandal绑定期间的竞争条件 - 无需承诺

时间:2013-08-02 17:12:11

标签: javascript knockout.js durandal

Durandal在页面组成/绑定周围存在明显的竞争条件。

之前在Stackoverflow上已经提出过有关此问题的问题,但给出的答案(已被接受)似乎掩盖了我认为会继续吸引人们的潜在竞争条件。

问题如下所述: Durandal KO Binding View Issue

这是有问题的代码:

define(function (require) {
var http = require('durandal/http');

return {
    subjectItem: function (data) {
        var self = this;
        self.Subject_ID = data.Subject_ID;
        self.Subject_Name = data.Subject_Name;
    },
    subjects: ko.observableArray([]),
    activate: function () {
        var self = this;
        http.ajaxRequest("get", "/api/values/getsubjects")
            .done(function (allData) {
                var mappedSubjects = $.map(allData, function (list) { return new self.subjectItem(list); });
                self.subjects(mappedSubjects);
            });
    }
};
});

这个问题的答案是,activate函数应该返回ajax调用的结果,这是一个promise。这将导致Durandal在继续进入绑定阶段之前等待ajax调用完成。

答案的问题是没有理由等待ajax调用完成。上面的viewmodel已经包含一个空的observableArray,它应该成功绑定到有或没有任何元素的模板。如果ajax调用完成,则添加到observableArray的新数据将被添加到页面中。

这可以证明如下。而不是在进行绑定的同时触发ajax调用,使用setTimeout在绑定完成后触发ajax调用。执行此操作时,将避免竞争条件,并且每次页面都有效。

这是修改后的代码:

define(function (require) {
var http = require('durandal/http');

return {
    subjectItem: function (data) {
        var self = this;
        self.Subject_ID = data.Subject_ID;
        self.Subject_Name = data.Subject_Name;
    },
    subjects: ko.observableArray([]),
    activate: function () {
        var self = this;
        setTimeout(function () {
          http.ajaxRequest("get", "/api/values/getsubjects")
              .done(function (allData) {
                  var mappedSubjects = $.map(allData, function (list) { return new self.subjectItem(list); });
                  self.subjects(mappedSubjects);
              });
        },1500);
    }
};
});

只有在页面绑定期间更新observableArray时才会断页。如果setInterval在后台运行,定期刷新一个长期存在的observableArray,这可能随时发生(似乎是随机的)。

所以我的问题是,如果这不是Durandal中的竞争条件,当observableArrays异步更新并与页面绑定同时更新时,为什么我们会看似随机破坏,但是在绑定完成后更新observableArray时没有破损?

更新: 我找到了一种非常简单的方法来触发这个问题。假设你的viewmodel中有一个observableArray可以作为“firewallList”(我这样做)访问,这将触发问题:

function activate() {
    var counter=0;
    var timer=setInterval(function() {
        counter++;
        if(counter > 20) {
            clearInterval(timer);
            return;
        }
        firewallList.push(new Firewall({id: counter, name: 'item'+counter, description: 'description'+counter}));
    }, 10);

}

取决于我如何改变间隔值,我会得到不同的结果。当它是10ms时,我最终得到表中显示的一行。如果我把它降到7毫秒,我会在表格中得到一行或两行。后续对象确实被添加到observableArray,但从未进入DOM。触发此问题后,对observableArray的任何操作都不会导致对DOM的任何更新。

0 个答案:

没有答案