I am trying to create what I think is referred to as a "Waterfall". I want to sequentially process an array of async functions (jQuery promises).
Here's a contrived example:
function doTask(taskNum){
var dfd = $.Deferred(),
time = Math.floor(Math.random()*3000);
setTimeout(function(){
console.log(taskNum);
dfd.resolve();
},time)
return dfd.promise();
}
var tasks = [1,2,3];
for (var i = 0; i < tasks.length; i++){
doTask(tasks[i]);
}
console.log("all done");
I would like it to complete the task in the order they are executed (present in the array). So, in this example I want it to do task 1 and wait for it to resolve then do task 2 wait for it to resolve, do task 3 etc and the log "all done".
Maybe this is really obvious but I've been trying to figure this out all afternoon.
You can create a resolved $.Deferred and just add to the chain with each iteration:
Step by step the following is happening:
Personally, I find this cleaner than recursion and more familiar than $().queue (jQuery API for $().queue is confusing as it is designed for animations, it is also likely you are using $.Deferred's in other places in your code). It also has the benefits of standard transfer of results down the waterfall through resolve() in the async operation and allowing the attachment of a $.done property.
Here it is in a jsFiddle
Have a look at the $.when and then methods for running deferreds.
Waterfalls are used to pipe return values from one deferred to the next, in series. It would look something like this.
Note the argument passed to
resolve
. That gets passed to the next function in the chain. If you just want to run them in series without piping in arguments, you can take that out and change the reduce call to.reduce(function(chain, taskNum) { return chain.then(doTask.bind(null, taskNum)); }, doTask(tasks[0]));
And in parallel it would look like this:
Arguments
Simple Loop:
Track Progress:
I'd try using
$().queue
instead of$.Deferred
here. Add the functions to a queue, and only call the next one when ready.For a waterfall, you need an async loop:
Interesting challenge indeed. What I have come up with is a recursive function that accepts a list and an optional start index.
Here is a link to the jsFiddle that I have tested with a few different list lengths and intervals.
I'm assuming you have a list of functions that return promises (not a list of numbers). If you do have a list of numbers you would change this part
to this
I'm not sure how big your list of functions could be but just be aware that the browser will hold on to the resources from the first deferredSequentialDo call until they are all finished.