Last Updated: February 25, 2016
·
1.477K
· sschepis

Clean up that ugly node.js callback hierarchy with async.waterfall

Node.js is awesome but all those asynchronous nested callbacks sure do make for some hard to read code - for example the case below, where foo(), bar(), and baz() are called in succession:

foo(function(err, ret) {
    // ...
    if(err) return handleError(err);
    else bar(function(err, ret) {
        // ...
        if(err) return handleError(err);
        else baz(function(err, ret) {
            // ...
            if(err) return handleError(err);
            else console.log('we are done');
        }
    }
}

The code above hurts my eyeballs, and it should hurt yours too, because we both know that the above example is tame compared to the real world and that nested callback handlers become unreadable after just a few indentations. That's hard to read and hard to debug.

Luckily there are alternatives to this mess. One of my favorites is async.waterfall():

async.waterfall([
    function(next) {
        foo(next);
    },
    function(data, next) {
         bar(next);
    },
    function(data, next) {
        baz(next);
    }
],
function(){
    if(err) return handleError(err);
    else console.log('we are done');
}); 

Or if you have no other code to call but the three functions (and they all follow standard node.js callback convention):

async.waterfall([
    foo, 
    bar, 
    baz],
    function(err, out) {
            if(err) return handleError(err);
            else console.log('we are done');
    });

async is awesome because smart flow control is awesome and necessary and it keeps you sane. Thank you, async.