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的任何更新。