async.jsでフロー制御

よく分からなくなるのでメモ。
Nodeの非同期を扱うライブラリasync。の機能でフロー制御関数が幾つかある。

var async = require('async');

async.waterfall([
    function (callback) {
        console.log('waterfall 1');
        setTimeout(function () {
            console.log('waterfall 1 done.');
            callback(null, 1);
        }, 500);
    },
    function (arg, callback) {
        console.log('waterfall 2');
        setTimeout(function () {
            console.log('waterfall 2 done.');
            callback(null, arg + 1);
        }, 300);
    },
    function (arg, callback) {
        console.log('waterfall 3');
        setTimeout(function () {
            console.log('waterfall 3 done.');
            callback(null, arg + 1);
        }, 100);
    }
], function (err) {
    if (err) { throw err; }
    console.log('waterfall all done.');
});

async.series([
    function (callback) {
        console.log('series 1');
        setTimeout(function () {
            console.log('series 1 done.');
            callback(null, 1);
        }, 500);
    },
    function (callback) {
        console.log('series 2');
        setTimeout(function () {
            console.log('series 2 done.');
            callback(null, 2);
        }, 300);
    },
    function (callback) {
        console.log('series 3');
        setTimeout(function () {
            console.log('series 3 done.');
            callback(null, 3);
        }, 100);
    }
], function (err, results) {
    if (err) { throw err; }
    console.log('series all done. ' + results);
});

async.parallel([
    function (callback) {
        console.log('parallel 1');
        setTimeout(function () {
            console.log('parallel 1 done.');
            callback(null, 1);
        }, 500);
    },
    function (callback) {
        console.log('parallel 2');
        setTimeout(function () {
            console.log('parallel 2 done.');
            callback(null, 2);
        }, 300);
    },
    function (callback) {
        console.log('parallel 3');
        setTimeout(function () {
            console.log('parallel 3 done.');
            callback(null, 3);
        }, 100);
    }
], function (err, results) {
    if (err) { throw err; }
    console.log('parallel all done. ' + results);
});

console.log('done.');

実行結果は

$ node example.js
series 1
parallel 1
parallel 2
parallel 3
done.
waterfall 1
parallel 3 done.
parallel 2 done.
series 1 done.
series 2
parallel 1 done.
parallel all done. 1,2,3
waterfall 1 done.
waterfall 2
series 2 done.
series 3
waterfall 2 done.
waterfall 3
series 3 done.
series all done. 1,2,3
waterfall 3 done.
waterfall all done.

という感じ。
seriesは名前の通り引数に渡されたfunction配列の順番に実行。予め渡されるcallbackが呼ばれると次のものが呼ばれる、という仕組み。
parallelはseriesと同じ形式で渡されたものを全部並行で走らせる。
waterfallはseriesに近いけど前の関数から引数を受け取ることができる。順番に処理したいけど前の処理で得たデータを使用したい、というときに便利かも。
いずれもすべての関数の実行が終了したタイミングで第2引数で渡された関数が呼び出される。