How To Convert Step Code To Async.js (step => Waterfall, This.parallel)?
A couple years ago I was experimenting with NodeJS and found that the 'Step' library cleaned up some of my code rather nicely. When desiring to bring that code up to date, I notic
Solution 1:
As requested, an implementation of what you are doing with promises. Just paste and run and you should get the idea. Bear in mind the top half of the code is setting up simulated functions so you can better follow along how this works. Someone will probably tell me I should have done this as a gist, which I may do as well.
var Q = require('q');
var foo ={}, bar ={}, baz = {};
// let's mock up some of your objects with some asynch functions// using setTimeout for async completion
foo.asyncCall = function ( cb) {
setTimeout(function(){ cb(null, 'promises'); },500);
};
bar.asyncCall = function ( arg1, arg2, cb) {
setTimeout(function(){
var result = arg1 + ' can be ' + arg2;
cb(null, result);
},1200);
};
// going to add a will-always-fail function for example purposes
bar.asyncFailure = function (arg1, arg2, cb){
setTimeout(function(){
cb(newError(arg1 +' offer decent error handling'), null);
},2000); // longer delay - simulate a timeout maybe
};
baz.asyncCall = function ( arg1, arg2, cb) {
setTimeout(function(){
var result = arg1 + ' are really ' + arg2;
cb(null, result);
},800);
};
// set up promise-enbaled calls. Q.denodeify is an easy way to deal with any// standard node function with a final parameter being an (err,data) callback// If these are your own functions, you can also create your own promises, but// Q.nodeify is probably the fastest way to adapt existing code.
bar.promiseFailure = Q.denodeify(bar.asyncFailure);
bar.promiseCall = Q.denodeify(bar.asyncCall);
baz.promiseCall = Q.denodeify(baz.asyncCall);
// this is your wrap up call ('thirdStep' in your code)functionallTogetherNow(arg1, arg2) {
console.log(arg1 +'\n' + arg2);
};
// now we can have some fun// an example that will run to completion normally// Q.ninvoke is sort of a 'one-time' denodeify, it invokes a node-style function// and returns a promisefunctionexample(){
Q.ninvoke(foo,'asyncCall')
.then( function (x) {
return [bar.promiseCall(x, 'confusing at first'),
baz.promiseCall(x, 'awesome after that')]
})
.spread(allTogetherNow)
.fail(function(e){console.log('Had an error')})
.finally(function(){console.log('Calling no matter what from example')});
};
// sometimes things aren't entirely fun though, and there can be an errorfunctionexample2(){
Q.ninvoke(foo,'asyncCall')
.then( function (x) {
return [bar.promiseFailure(x, 'confusing at first'),
baz.promiseCall(x, 'awesome after that')]
})
.spread(allTogetherNow)
.fail(function(e){console.log(e)})
.finally(function(){console.log('Calling no matter what from example2')});
};
example();
example2();
For those that don't want to bother running it, the output emitted is:
promises can be confusing atfirst
promises are really awesome after that
Calling no matter what from example
[Error: promises offer decent error handling]
Calling no matter what from example2
Solution 2:
Be careful with your callbacks, here. The callback signature is:
callback(err, arg1, arg2 ...)
So if your foo.asyncCall
were to call it with:
callback(result1, result2)
Then the whole async would mysteriously fail from that point. The correct callback for success should start with a null, e.g.
callback(null, result1, result2)
Here is the corrected code:
function thirdStep(argFromBar, argFromBaz, callback) {
/* etc... */callback(null, result);
}
async.waterfall([
function firstStepNoArgs(callback) {
// error callback("failed"). First args is not null means failed// in case of error, it just goes straight to function(err, result)
foo.asyncCall(callback);
},
function secondStep(argFromFoo, callback) {
// argFromFoo come from previous callback (in this case, result1)
async.parallel([
barResult: function(callback) {
bar.asyncCall(parameterFromFoo, 1, callback);
},
bazResult: function(callback) {
baz.asyncCall(parameterFromFoo, 2, callback);
}
],
function(err, result) {
if (err) {
// in case of error you should do callback(error),// this callback is from secondStep(argFromFoo, callback).// this will pass to final function(err, result).handleError(err);
} else {
// you need to do callback(null) inside thirdStep// if callback is not called, the waterfall won't completethirdStep(result.barResult, result.bazResult, callback);
}
}
}
],
function(err, result) {
if (err) {
handleError(err);
} else {
// everything is executed correctly, // if any step failed it will gone to err.
}
}
);
Post a Comment for "How To Convert Step Code To Async.js (step => Waterfall, This.parallel)?"