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

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

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

さらに、ECMAScript6からは非同期処理を扱うためのPromiseオブジェクトが標準で使用できます。
[ECMAScript6のアロー関数とPromiseまとめ - JavaScript](http://qiita.com/takeharu/items/c23998d22903e6d3c1d9)

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

RSSはこちら
Feedly: [Feedlyをフォロー]
(http://cloud.feedly.com/#subscription%2Ffeed%2Fhttp%3A%2F%2Fqiita.com%2Ftakeharu%2Ffeed)
RSS: http://qiita.com/takeharu/feed

#waterfall

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

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

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


```javascript:
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の引数に渡した値ですが、
最後にまとめてこの配列の順番のまま、配列に値が代入されています。

```javascript:
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に渡した引数はまとめて最後に配列となって、
この順番通りに代入されています。


```javascript:
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に関数を代入する方法があります。

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

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

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

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

```javascript:
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]
(https://twitter.com/takeharumikami)

RSSはこちら
Feedly: [Feedlyをフォロー]
(http://cloud.feedly.com/#subscription%2Ffeed%2Fhttp%3A%2F%2Fqiita.com%2Ftakeharu%2Ffeed)
RSS: http://qiita.com/takeharu/feed

# おすすめの記事

ECMAScript6からは非同期処理を扱うためのPromiseオブジェクトが標準で使用できます。
[ECMAScript6のアロー関数とPromiseまとめ - JavaScript](http://qiita.com/takeharu/items/c23998d22903e6d3c1d9)

入門者がつまづく、thisの挙動を4種類に分けて簡単に学ぶならこれ。Apply, callの挙動までわかる。
[JavaScriptの「this」は「4種類」？」](http://qiita.com/takeharu/items/9935ce476a17d6258e27)

JavaScriptでは関数型言語の一部の機能？実践的なJavaScriptの関数型とは。
[JavaScriptで関数型プログラミングの入門](http://qiita.com/takeharu/items/cf98d352ff574c5ac536)