jQuery:按顺序执行函数数组(延迟和非延迟)

我使用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 你正在寻找的。 它需要一个承诺或一个普通的非可重复的东西,并返回一个超过该值的承诺。 但是,由于这里有函数而不是值.then无论如何都是.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` } 

( 小提琴 )

或者,你可以减少;

 var res = queue.reduce(function(prev,cur){ // chain to res later to hook on done return prev.then(cur); }, $.Deferred().resolve()); 

如果你有更多的代码在下面执行操作,因为队列中的函数可以同步或异步运行(或者某些同步,然后我们遇到异步),为了避免混乱,你可能希望确保函数总是异步运行。 您可以通过将resolve包装在setTimeout的初始Deferred 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的承诺的语义不一致(因为它们在同步与异步回调方面不一致 ),但您可能需要一致性。

如果您需要知道进程何时完成,只需在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); } 

使用示例( 小提琴 ):

 clearQueue(queue).then(function() { console.log("All done"); }); console.log("This runs before any queued function starts");