2

在 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 调用的结果,这是一个承诺。这将导致 Durandal 在继续绑定阶段之前等待 ajax 调用完成。

这个答案的问题是没有理由等待 ajax 调用完成。上面的视图模型已经包含一个空的 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 时没有损坏?

更新:我找到了一种非常简单的方法来触发这个问题。假设您的视图模型中有一个 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);

}

根据我如何改变间隔值,我得到不同的结果。当它是 10 毫秒时,我最终会在表格中显示一行。如果我将它降低到 7 毫秒,我的表中会出现一到两行。后续对象确实会添加到 observableArray,但永远不会添加到 DOM。一旦触发了这个问题,对 observableArray 的任何操作都不会导致对 DOM 的任何更新。

4

0 回答 0