JavaScriptのasync.jsでwaterfallとseries、parallelの違い

  • 222
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

async.js

主にnodeで使用されている、javascriptの非同期処理を扱うライブラリです。
フロントエンドでもゲーム作り等では重宝するんです。

その中でも使用率がかなり高い、waterfallとseries、そしてparallelの三つについて簡単にまとめました。

さらに、ECMAScript6からは非同期処理を扱うためのPromiseオブジェクトが標準で使用できます。
ECMAScript6のアロー関数とPromiseまとめ - JavaScript

技術情報のみつぶやくアカウント作成しました。JavaScriptなどの最新情報も追っていきます。
Twitter: @takeharumikami

RSSはこちら
Feedly: Feedlyをフォロー
RSS: http://qiita.com/takeharu/feed

waterfall

まず、waterfallについてです。
配列の順番で、この場合は上の関数から実行されていきます。

この際に引数に与えられたcallbackの関数が実行されるまで、
次の関数の処理には移行しません。

そしてcallbackの関数の第一引数にはerrorを、
第二引数以降は次の関数に渡したい引数を選ぶ事ができます。

async.waterfall([
  function(callback) {
    console.log('1');
    setTimeout(function() {
      console.log('1 done');
      callback(null, 1);
    }, 100);
  },
  function(arg1, callback) { // arg1 === 1
    console.log('2');
    setTimeout(function() {
      console.log('2 done');
      callback(null, 1, 2);
    }, 50);
  },
  function(arg1, arg2, callback) { // arg1 === 1, arg2 === 2
    console.log('3');
    setTimeout(function() {
      console.log('3 done');
      callback(null, 1, 2, 3);
    }, 10);
  }
], function(err, arg1, arg2, arg3) { // arg1 === 1, arg2 === 2, arg3 === 3
  if (err) {
    throw err;
  }
  console.log('all done.');
  console.log(arg1, arg2, arg3);
});

//出力結果
1
1 done
2
2 done
3
3 done
all done
1 2 3

series

seriesの流れはwatarfallの制御の流れと同じです。

配列の順番に、この場合は上から順次実行されていきます。
そして、次の関数に処理が移るにはcallbackが呼ばれる必要があります。

違いはcallbackの引数に渡した値ですが、
最後にまとめてこの配列の順番のまま、配列に値が代入されています。

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

//出力結果
1
1 done
2
2 done
3
3 done
all done
[1, 2, 3]

parallel

最後にparallelです。
seriesやwaterfallと違い、並列に処理されます。
(厳密には並列ではないですが)

ですから引数に渡されたcallbackでは次の関数が呼ばれません。

callbackに渡した引数はまとめて最後に配列となって、
この順番通りに代入されています。

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

//出力結果
1
2
3
3 done
2 done
1 done
all done
[1, 2, 3] 

parallelは並列処理なので、
配列に関数を代入しなくてもいいです。

そこで別パターンとしてオブジェクトの各valueに関数を代入する方法があります。

この場合の違いは二点です。

1:並列処理の開始が保証されない
2:callbackに渡した値が、最後にまとめてオブジェクトに代入されている

1は配列の時と違い、どこから実行されるか保証されていないということです。
配列のときは要素の0から実行されていきます。

2は下記を見てもらえればわかるのですが、
同じkeyに対応して渡された値が代入されています。

async.parallel({
  first: function(callback) {
    console.log('1');
    setTimeout(function() {
      console.log('1 done');
      callback(null, 1);
    }, 100);
  },
  second: function(callback) {
    console.log('2');
    setTimeout(function() {
      console.log('2 done');
      callback(null, 2);
    }, 50);
  },
  third: function(callback) {
    console.log('3');
    setTimeout(function() {
      console.log('3 done');
      callback(null, 3);
    }, 10);
  }
}, function(err, results) {
  if (err) { 
    throw err;
  }
  console.log('all done');
  console.log(results);
});

// 出力結果
1
2
3
3 done
2 done
1 done
all done
{ third: 3, second: 2, first: 1 }

まとめ

コールバック処理はjavascriptでは重要な要素ですよね。

asyncを使うとスパゲッティにもなりづらいですし、
うまく扱えるとかなり重宝しますので、ぜひぜひおすすめです。

アカウント

技術情報のみつぶやくアカウント作成しました。JavaScriptなどの最新情報も追っていきます。
Twitter: @takeharumikami

RSSはこちら
Feedly: Feedlyをフォロー
RSS: http://qiita.com/takeharu/feed

おすすめの記事

ECMAScript6からは非同期処理を扱うためのPromiseオブジェクトが標準で使用できます。
ECMAScript6のアロー関数とPromiseまとめ - JavaScript

入門者がつまづく、thisの挙動を4種類に分けて簡単に学ぶならこれ。Apply, callの挙動までわかる。
JavaScriptの「this」は「4種類」?」

JavaScriptでは関数型言語の一部の機能?実践的なJavaScriptの関数型とは。
JavaScriptで関数型プログラミングの入門