blog.bouzuya.net

2014-05-03 Promise で async ライクな機能をつくった

bouzuya/promise-async-exampleをつくった。README.md にも書いたのだけれど、これは Promise の練習プロジェクト。何をしているのかを順に説明していく。

最近は Promise をコールバックの代替として使っている。完全に置き換わることはないだろうけど、少なくとも jQueryDeferred の類は言語機能として提供される Promise に置き換えられると考えて、その準備として試している感じ。

しかし、Promise を使っていると、順次実行がやりづらいときがある。具体的な例を挙げると [1, 2, 3] に対して、それぞれ非同期の f に適用するのだけれど、それぞれを並列ではなく順次実行してほしいときがある。要するに caolan/asyncmapSeries がほしくなる。並列実行は Promise.all を使えば簡単にできるのだけれど、順次実行はちょうど良い関数は提供されていない。

Promise でもおなじことをできるはずなのだけれど、考える時間がもったいないからと async をインストールしたりしていて、それはあんまりだと感じたので、今回の練習プロジェクトをつくって、今後は Promise 一本でやろうと思っている。

練習プロジェクトの中身を説明。

まず eachSeries を書いてみたPromise.all でやると並列実行されることを確認して、then を数珠つなぎに書けば順次実行できることを確認して、reduce を使って可変なものに対応できるようにして、最後に汎用化する。

次に mapSeries を書いてみたeachSeries で戻り値を保持すれば良いだけなので、そんなに難しくない。愚直だけど、results にまとめて返す。

おまけで waterfall を書いてみたwaterfall は順次実行で前の結果を次に渡す。これも簡単。

ちなみに上記、三つをまとめたものはここ。たぶん、都度書けば良いレベルだと思うので、パッケージにはしていない。

async より優れている点として引数の callback の位置を気にしなくて良い。一個引数を増やしたから動かない、なんてことがない。単純に結果を返しても、非同期なら Promise を返しても良い。不自然なルールがなくて気持ち良い。