非常精明,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());
如果你有更多的代码在下面做一些事情,因为队列中的函数可能同步或异步运行(或者一些同步然后我们点击异步),为了避免混乱,你可能希望确保函数始终运行异步。您可以通过将初始 Deferred 上的 resolve 包装在 setTimeout 中轻松做到这一点:
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 承诺的语义不一致(因为 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");