Here we compose sequences and gates from asynquence to handle "nested" async tasks:
var elems = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
// turn the array of numbers into an array of sequences
var segments = elems.map(processElement);
ASQ()
// parallel gate of processing for all elements
.all.apply(null,segments)
// now we can inspect once all element processing is done
.val(function(){
console.log(arguments);
// [ 7, 28, 21, 56, 35, 84, 49, 112, 63, 140 ]
})
// oops, something went wrong somewhere along the way
.or(function(failMsg){
console.log(failMsg);
});
function processElement(el) {
return ASQ(function(done){
setTimeout(function(){
// check if we need to fail element processing
if (el > 10) done.fail("too big: " + el);
else done(el);
},1000);
})
// delegate even more processing to a "nested" sequence,
// and implicitly pipe that nested sequence's output
// back into our sequence
.seq(moreElementProcessing);
}
function moreElementProcessing(el) {
return ASQ(function(done){
setTimeout(function(){
// let's double only the evens
if (el % 2 === 0) el *= 2;
done(el);
},1000);
})
// do even more processing (this time in parallel)
.all(
function(done,el){
setTimeout(function(){
// we could fail even really deep, and it will still propagate out
if (el === 72) done.fail("I don't like this number: " + el);
else done(el * 3);
},100);
},
function(done,el){
setTimeout(function(){
done(el * 4);
},50);
}
)
// re-combine the separately processed (gate) values back into
// one value for each element
.val(function(el_1,el_2){
return el_1 + el_2;
});
}