記録として残しておきたいブログ

主にプログラミングについて書きます。現在は http://tmg0525.hatenadiary.jp/ に書いています。

Node.jsで非同期処理をフロー制御する<asyncモジュール>

環境

OS : Windows10
Node.js : v6.9.4

Node.jsは非同期処理

Node.jsは非同期処理をするプログラミング言語

順番に処理するためにコールバック関数を利用する。

コールバック関数でも対処できるがネストが多くなって見た目が良くない。


ここで、asyncモジュールを使う。

asyncモジュール

・モジュールのインストール方法こちら
・asyncの公式ドキュメントはこちら



series()<順次実行>

  • async.seriesのドキュメント
  • それぞれの関数を実行し、完了したら次に定義されている関数を順次実行していく。
  • メインコールバック関数のresultsには各関数のresultが格納されている。

例)

// test0.js
const async = require('async');
console.log('start');

async.series([
    function(callback) {    // 1番目に実行される関数
        console.log('function1');
        setTimeout(function() {
            console.log('done function1');
            callback(null, 'one');
        }, 3000);
    },
    function(callback) {    // 1番目の関数が完了したら呼ばれる
        console.log('function2');
        setTimeout(function() {
            console.log('done function2');
            callback(null, 'two');
        }, 2000);
    },
    function(callback) {    // 2番目の関数が完了したら呼ばれる
        console.log('function3');
        setTimeout(function() {
            console.log('done function3');
            callback(null, 'three');
        }, 1000);
    }
], function(err, results) { // 3番目の関数が完了したら呼ばれる
    console.log(results);   // resultsには [ 'one', 'two', 'three' ] が格納されている
    console.log('end');
});

test0.jsの実行結果

start
function1
done function1
function2
done function2
function3
done function3
[ 'one', 'two', 'three' ]
end

配列の最初から実行し、完了したら次の関数を順次実行している。


series(tasks, callback)

引数

  • tasks <Array | oterable | Object>
    • 順番に実行したい関数の配列。
    • 各関数ではcallback(err, result)を呼ばないといけない。
    • errにはnullかエラー、resultには結果
  • callback <function>
    • すべての関数の実行が終わったら呼ばれる関数(メインコールバック関数っていうらしい)
    • 各関数のresultを配列で受け取り、呼ばれる。

処理

  • 各関数のcallback()で次の関数を呼んでいる
  • 順番に関数を実行していき、途中でエラーが起きた場合はその関数以降の関数は実行しない。
    • そして、メインコールバック関数にエラー値を渡し、呼ばれる。

parallel() <並列実行>

  • async.parallelのドキュメント
  • 同時にすべての関数を実行して、完了したらメインコールバック関数を呼ぶ。

以下のコードはtest0.jsの4行目の series を parallel に変えただけ

// test1.js
const async = require('async');
console.log('start');

async.parallel([
    function(callback) {        // ③
        console.log('function1');
        setTimeout(function() {
            console.log('done function1');
            callback(null, 'one');
        }, 3000);
    },
    function(callback) {        // ②
        console.log('function2');
        setTimeout(function() {
            console.log('done function2');
            callback(null, 'two');
        }, 2000);
    },
    function(callback) {        // ①
        console.log('function3');
        setTimeout(function() {
            console.log('done function3');
            callback(null, 'three');
        }, 1000);
    }
], function(err, results) {    // resultsには [ 'one', 'two', 'three' ]
    console.log(results);
    console.log('end');
});

test1.jsの実行結果

start
function1
function2
function3
done function3
done function2
done function1
[ 'one', 'two', 'three' ]
end

まず、すべての関数を実行している。
今回はsetTimeoutで各関数の実行開始を遅らせている。
①→②→③の順番で関数が実行される。
すべて完了したらメインコールバック関数が呼ばれる。


parallel(tasks, callback)
引数

  • tasks <Array | oterable | Object>
    • 実行したい関数の配列。
    • 各関数ではcallback(err, result)を呼ばないといけない。
    • errにはnullかエラー、resultには結果
  • callback <function>
    • すべての関数が正常に完了すると呼ばれる。
    • 各関数のresultを配列で受け取り、呼ばれる。tasksの順番で格納されている。

処理

  • 関数の完了を待たずに、並列に実行する。
    • もし、エラーが起きたら、メインコールバック関数にエラー値を渡し、メインコールバック関数が呼ばれる。
    • 正常に関数が完了したら、resultsがメインコールバックの配列に渡される。
  • parallelは関数を並列実行する。
    • 各関数内でタイマーを使用しない、I/Oをしないときは、連続して処理されることと同じになる。

waterfall() <次の関数へ引数を渡す>

  • async.waterfallのドキュメント
  • 順番に実行していくのはseries()と同じであるが、前の関数から引数を受け取ることができる
    • 前の関数の結果によって処理内容が変わるときに使える
  • メインコールバック関数に渡される引数は最後の関数ののcallback()の引数になる
// test2.js
const async = require('async');

async.waterfall([
    function(callBack) {
        console.log('1');
        callBack(null, 'one', 'two'); // 次の関数に引数を渡す
    },
    function(args1, args2, callBack) {
        console.log('2');
        console.log('args1:' + args1);
        console.log('args2:' + args2);
        callBack(null, 'done');         // メインコールバック関数に引数を渡す
        // callBack(null, ['done', 'end']);  // 複数渡すときは配列で渡す
    }
],
function(err, results) {    // resultsには 'done' のみ格納されている
    console.log(results);
});

test2.jsの実行結果

1
2
args1:one
args2:two
done


waterfall(tasks, callback)
引数

  • tasks
    • 実行する関数の配列
    • 各関数でcallback(err, result1, result2, ...)を呼び出さなければならない
    • errはnullかエラー、それ以降の引数は次の関数に渡される。
  • callback
    • すべての関数を実行したらこの関数を実行する。
    • 各関数のresultを配列で受け取り、呼ばれる。

処理

  • 順番に関数を実行し、次の関数に結果を渡す
  • 途中でエラーが起きたら、それ以降の関数は実行せずにメインコールバック関数が呼ばれる。


ほかにも使える機能がたくさんあるそうなのでいろいろ使ってみたいです。


参考サイト
dev.classmethod.jp
ameblo.jp