您不会“停止”,而是围绕您使用的任何环境的异步特性来设计应用程序。
我假设你正在尝试做这样的事情:
function getInvites(id){
var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
var invites;
InvitesTable.read({ success: function(resultss) {
invites = resultss;
}});
return invites;
}
// later...
var invites = getInvites(someId);
//do something with `invites`
这显然是行不通的,因为您invites
在异步调用完成之前返回值。
相反,您以异步风格编写应用程序:
function getInvites(id, cb){
var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
InvitesTable.read({ success: function(resultss) {
if (cb) cb(resultss);
}});
}
// later...
getInvites(someId, function(invites) {
//do something with `invites`
});
为了简单起见,这省略了错误处理代码,因此您也必须添加它。
在查看完整代码后,您似乎遇到了管理许多并行异步操作的简单问题。考虑会发生什么:您的循环运行,迭代n 个对象的数组。对于每个,您调用getInvites
,它开始一个数据库请求并返回。
这意味着您的循环运行得非常快,但是现在您有n 个未完成的数据库请求,您必须等待才能调用request.respond()
.
一个非常基本的解决方案是计算调用回调的次数getInvites
,然后在该次数达到n时最终完成请求。
但是,每次发出异步请求时手动管理此簿记既费时又容易出错。这是流控制库非常有用的情况。我将Deferred
在这个例子中使用 jQuery,因为它可能对你来说已经很熟悉了(即使你不知道你以前实际使用过它——如果你曾经使用过 jQuery 的 XHR API,那么你已经使用过Deferred
s)。
鉴于您处于服务器环境中,您显然没有 jQuery;但是,有些人只提取了您所需的代码Deferred
。
一旦我们Deferred
为每个待处理的请求设置了 s,我们就可以使用它来注册一个回调,该回调仅在所有待处理的 s 完成when
后才被调用。Deferred
function read(query, user, request) {
request.execute({
success: function(results) {
var dfds = [];
for (var i = 0; i < results.length; i++) {
dfds.push(getInvites(results[i].id)); // Makes an array of Deferreds representing
// each of our pending requests.
}
Deferred.when.apply(Deferred, dfds) // see details below
.done(function() {
for (var i = 0; i < results.length; i++) {
results[i].invites = arguments[i]; // Copy each set of invites to each result
}
request.respond(); // We're done!
})
.fail(function() {
// Handle errors here
});
}
});
}
function getInvites(id){
var dfd = new Deferred(); // Create a new Deferred, which automatically starts in the 'pending' state
var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
InvitesTable.read({ success: function(results) {
dfd.resolve(results); // When we get data back, we 'resolve' the Deferred --
// in other words, say its operation is done,
// and pass along the operation's results.
},
error: function(err) { // TODO: Not sure if this is how the API you're using handles errors
dfd.reject(err); // Marks the Deferred as failed.
}});
return dfd.promise(); // We (synchronously) return the Promise. The caller can attach event handlers
// to the Promise, which are invoked when we eventually resolve or reject the Deferred.
}
笔记:
jQuery.when
(或在这种服务器端情况下,Deferred.when
)通常希望您传递固定数量的Deferred
s 作为参数:
$.when(dfd1, dfd2).done(function(result1, result2) { ... });
但是,我们有一个可变数量的Deferred
s,所以我们必须一个sapply
数组,然后在处理程序中,通过隐式对象访问每个结果。Deferred
when
done
arguments
Array.forEach(...)
很慢。在大多数情况下,最好使用常规for
循环。