我最近在我的代码中遇到了一个关于竞争条件的小问题。我正在使用Knockout.Js收集一些信息以显示给用户。
在可以选择值之前需要生成下拉列表时会发生故障。 通常下拉列表小于其他请求并将赢得比赛,因此不会造成任何问题。但是我在我的应用程序中看到了一些情况,在较慢的Internet连接上,列表第二次加载。以下是一个例子。如果列表中没有该值的选项,则无法选择该选项,并且对用户显示似乎没有选择一个选项。
使用setTimeout
我模拟了这种体验。您可以交换这两个值以查看"成功"场景。
function ViewModel() {
var self = this;
self.UserName = ko.observable();
self.UserGroup = ko.observable();
self.GroupList = ko.observableArray();
self.LoadUserGroups = function() {
//Ajax call to populate user groups
setTimeout(function() {
response = "Red Team,Blue Team,Green Team".split(",");
self.GroupList(response)
}, 2000) /// SWAP ME
}
self.LoadUserInformation = function() {
setTimeout(function() {
response = {
UserName: "John Pavek",
UserGroup: "Blue Team"
};
self.UserName(response.UserName);
self.UserGroup(response.UserGroup);
}, 1000) // SWAP ME
}
self.Load = function() {
self.LoadUserGroups();
self.LoadUserInformation();
}
self.Load();
}
ko.applyBindings(new ViewModel())

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
User Name:
<input data-bind="value: UserName" /> User Group:
<select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup"></select>
&#13;
我可以在我的代码,Vanilla或淘汰赛中添加什么来防止此问题发生而不会减慢整个体验?
答案 0 :(得分:2)
当UserGroup
尝试设置的值不在选项列表中时,选项覆盖LoadUserInformation
会发生什么。但您可以使用valueAllowUnset
告诉它不要担心未知值。然后它不会覆盖。
function ViewModel() {
var self = this;
self.UserName = ko.observable();
self.UserGroup = ko.observable();
self.GroupList = ko.observableArray();
self.LoadUserGroups = function() {
//Ajax call to populate user groups
setTimeout(function() {
response = "Red Team,Blue Team,Green Team".split(",");
self.GroupList(response)
}, 2000) /// SWAP ME
}
self.LoadUserInformation = function() {
setTimeout(function() {
response = {
UserName: "John Pavek",
UserGroup: "Blue Team"
};
self.UserName(response.UserName);
self.UserGroup(response.UserGroup);
}, 1000) // SWAP ME
}
self.Load = function() {
self.LoadUserGroups();
self.LoadUserInformation();
}
self.Load();
}
ko.applyBindings(new ViewModel())
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
User Name:
<input data-bind="value: UserName" /> User Group:
<select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup, valueAllowUnset: true"></select>
答案 1 :(得分:1)
除了LoadUserInformation
之前 从<{1}}获取信息之后,我们别无选择。但这根本不会减慢经验。
您需要将加载与显示信息的分开。在非承诺环境中,我让每个函数都接受回调,然后只有在我得到两个结果时才进行(调用&#34; show&#34;函数),请参阅 从技术上讲,当然,如果他们在用户信息之前到达,则不会阻止您显示这些组,您只需使用状态标记: 在承诺环境中,我有#34;加载&#34;函数返回promises,然后使用它们看起来像这样而不需要 ......使用ES2015 +参数解构语法变得更清晰:LoadUserGroups
注释:< / p>
&#13;
***
&#13;
function ViewModel() {
var self = this;
self.UserName = ko.observable();
self.UserGroup = ko.observable();
self.GroupList = ko.observableArray();
// *** Only loads, doesn't show
self.LoadUserGroups = function(callback) {
//Ajax call to populate user groups
setTimeout(function() {
callback("Red Team,Blue Team,Green Team".split(","));
}, 2000);
}
// *** Shows
self.ShowUserGroups = function(groups) {
self.GroupList(groups);
};
// *** Only loads, doesn't show
self.LoadUserInformation = function(callback) {
setTimeout(function() {
callback({
UserName: "John Pavek",
UserGroup: "Blue Team"
});
}, 1000);
};
// *** Shows
self.ShowUserInformation = function(info) {
self.UserName(info.UserName);
self.UserGroup(info.UserGroup);
};
self.Load = function() {
var groups = null, userInfo = null;
self.LoadUserGroups(function(g) {
groups = g;
checkDone();
});
self.LoadUserInformation(function(u) {
userInfo = u;
checkDone();
});
function checkDone() {
if (groups && userInfo) {
// *** We have both, show them
self.ShowUserGroups(groups);
self.ShowUserInformation(userInfo);
}
}
}
self.Load();
}
ko.applyBindings(new ViewModel())
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
User Name:
<input data-bind="value: UserName" /> User Group:
<select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup"></select>
&#13;
function ViewModel() {
var self = this;
self.UserName = ko.observable();
self.UserGroup = ko.observable();
self.GroupList = ko.observableArray();
// *** Only loads, doesn't show
self.LoadUserGroups = function(callback) {
//Ajax call to populate user groups
setTimeout(function() {
callback("Red Team,Blue Team,Green Team".split(","));
}, 2000);
}
// *** Shows
self.ShowUserGroups = function(groups) {
self.GroupList(groups);
};
// *** Only loads, doesn't show
self.LoadUserInformation = function(callback) {
setTimeout(function() {
callback({
UserName: "John Pavek",
UserGroup: "Blue Team"
});
}, 1000);
};
// *** Shows
self.ShowUserInformation = function(info) {
self.UserName(info.UserName);
self.UserGroup(info.UserGroup);
};
self.Load = function() {
var haveGroups = false, userInfo = null;
self.LoadUserGroups(function(groups) {
// *** No need to wait for the user info
self.ShowUserGroups(groups);
haveGroups = true;
checkDone();
});
self.LoadUserInformation(function(u) {
userInfo = u;
checkDone();
});
function checkDone() {
if (haveGroups && userInfo) {
// *** Show the user info
self.ShowUserInformation(userInfo);
}
}
}
self.Load();
}
ko.applyBindings(new ViewModel())
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
User Name:
<input data-bind="value: UserName" /> User Group:
<select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup"></select>
调用:checkDone
Promise.all([
self.LoadUserGroups().then(self.ShowUserGroups),
self.LoadUserInfo()
]).then(function(results) {
self.ShowUserInfo(results[1]);
});