Situation
Need to call several functions one after another (waterfall sequence). Each function should pass an argument to the next
1 | var Q = require('Q'); |
Manual sequence
Connect the promise-returning functions into a chain using .then
method
foo('a').then(bar).done();
Prints correctly the argument a
passed through.
foo arg=a
bar arg=a
I always use .done()
method to make sure any exceptions inside the chain
are not hidden.
Dynamic chains
Q promise library has an utility method for dealing with sequences. The first rule: place all functions that return promises into an array. Then create the chain using Array.reduce method
[foo, bar].reduce(function (chain, fn) {
return chain.then(fn);
}, Q('a')).done();
// prints
foo arg=a
bar arg=a
Notice that we pass the initial argument via the second argument Q('a')
to reduce
call.
Shorthand
Writing the reduce
chaining is boilerplate, and Q comes with
Q.when
that calls .then
for you and allows much shorter sequence notation:
[foo, bar].reduce(Q.when, Q('a')).done();
// prints
foo arg=a
bar arg=a
Starting things right
Passing the argument to foo
via Q('a')
is weird. Let's shift the functions
around to make the syntax more natural. The purpose of Q('a')
is to start the chain.
Well we want to start the chain with calling foo
! So we can move first function
from the array of promise-returning functions into the reduce
1 | [bar].reduce(Q.when, foo('a')).done(); |
It looks a little weird, but usually you have more than two functions to chain, and the syntax would look better.