我对使用 Promises 还很陌生,并且很难理解 jQuery deferreds。
我目前拥有的是在某个点执行的一组函数:
while (queue.length) {
(queue.shift())();
}
这样做的问题是,其中一些函数是异步的,但我需要它们一个接一个地运行。
因此,队列中的某些函数返回延迟函数(例如通过 jQuery.ajax()),而有些函数只是普通函数。我想知道是否可以按顺序执行它们(仅当前一个函数完成时才执行下一个函数)。
我想也许 jQuery.when 就是我正在寻找的,但我不知道到底如何做,我只是想到了这个:
var deferred = jQuery.Deferred();
while (queue.length > 0) {
deferred.done().then(queue.shift());
}
最佳答案
非常精明,jQuery.when
就是您正在寻找的东西。它接受一个 Promise 或一个普通的 non-thenable 并返回一个超过该值的 Promise。但是,由于这里有函数而不是值,所以这并不是真正需要的,因为无论如何这是 .then
的行为。
var queue = [syncFunction, syncFunc2, returnsPromiseAsync];
var d = $.Deferred().resolve();
while (queue.length > 0) {
d = d.then(queue.shift()); // you don't need the `.done`
}
( fiddle )
或者,您可以减少;
var res = queue.reduce(function(prev,cur){ // chain to res later to hook on done
return prev.then(cur);
}, $.Deferred().resolve());
如果您有更多代码在下面执行操作,由于队列中的函数可能同步或异步运行(或者某些同步,然后我们遇到异步),为了避免困惑,您可能需要确保函数始终运行异步地。您可以通过将 resolve
包装在 setTimeout
中的初始 Deferred
上轻松实现此目的:
var p = $.Deferred();
var res = queue.reduce(function(prev,cur){ // chain to res later to hook on done
return prev.then(cur);
}, p);
setTimeout(p.resolve.bind(p), 0);
现在,直到超时发生为止,该进程不会启动,并且此后的任何代码肯定会在队列中的第一个函数执行之前运行。在我看来,这与 jQuery promise 的语义不一致(因为 they are inconsistent about sync vs. async callbacks ),但您可能需要一致性。
如果您需要知道进程何时完成,只需在 res
上使用 .then
处理程序即可:
res.then(function() {
// All functions have now completed
});
对于这些情况,这里有一个简单的包装函数,可以同时执行这两种操作:
function clearQueue(q) {
var p = $.Deferred();
setTimeout(p.resolve.bind(p), 0);
return q.reduce(function(prev,cur){
return prev.then(cur);
}, p);
}
使用示例(fiddle):
clearQueue(queue).then(function() {
console.log("All done");
});
console.log("This runs before any queued function starts");
关于jQuery:按顺序执行函数数组(延迟和非延迟),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24931115/