Reputation: 12542
In Mixu's Node.js book, there is a very awesome section about control flow. The following pattern allows you to chain async requests in series to make sure an event has completed before calling the next one. I'd like to modify this so that the response from one async request can then passed as an argument to the next.
Any ideas?
http://book.mixu.net/node/ch7.html http://jsfiddle.net/B7xGn/
function series(callbacks, last) {
var results = [];
function next() {
var callback = callbacks.shift();
if(callback) {
callback(function() {
results.push(Array.prototype.slice.call(arguments));
next();
});
} else {
last(results);
}
}
next();
}
// Example task
function async(arg, callback) {
var delay = Math.floor(Math.random() * 5 + 1) * 100; // random ms
console.log('async with \''+arg+'\', return in '+delay+' ms');
setTimeout(function() { callback(arg * 2); }, delay);
}
function final(results) { console.log('Done', results); }
series([
function(next) { async(1, next); },
function(next) { async(2, next); },
function(next) { async(3, next); },
function(next) { async(4, next); },
function(next) { async(5, next); },
function(next) { async(6, next); }
], final);
Upvotes: 0
Views: 112
Reputation: 43718
You can change the next
function signature so that you can pass it a result
. Here's how you could do it.
function series(callbacks, last) {
var results = [];
function next(result) {
var callback = callbacks.shift();
if(callback) {
callback(function(result) {
results.push(Array.prototype.slice.call(arguments));
next(result);
}, result);
} else {
last(results);
}
}
next();
}
// Example task
function async(arg, callback) {
var delay = Math.floor(Math.random() * 5 + 1) * 100; // random ms
console.log('async with \''+arg+'\', return in '+delay+' ms');
setTimeout(function() { callback(arg * 2); }, delay);
}
function final(results) { console.log('Done', results); }
series([
function(next) { async(1, next); },
function(next, result) { console.log('result: ', result); async(2, next); },
function(next, result) { console.log('result: ', result); async(3, next); },
function(next, result) { console.log('result: ', result); async(4, next); },
function(next, result) { console.log('result: ', result); async(5, next); },
function(next, result) { console.log('result: ', result); async(6, next); }
], final);
EDIT:
To be able to pass multiple results, you could simply change the series function to:
function series(callbacks, last) {
var results = [];
function next() {
var callback = callbacks.shift(), args;
if(callback) {
callback.apply(this, (args = [
function() {
results.push(Array.prototype.slice.call(arguments));
next.apply(this, arguments);
}
]).concat.apply(args, arguments));
} else {
last(results);
}
}
next();
}
Upvotes: 1