async.js を使ってみる
callback 地獄に陥りやすい javascript さんを救うべくして現れた async.js 。
機能の解説や使い方は他の方が詳しくやっていると思うので、
- caolan/async · GitHub 公式とか
- node.jsのいろいろなモジュール17 – asyncで非同期処理のフロー制御 | Developers.IO Developers.IOとか
- JavaScript - async.jsでwaterfallとseries、parallelの違い - Qiita Qiitaとか
あたりをご覧いただければと。
で、今回は自分で使ってて「ん?」と思った部分を紹介。
async = require 'async' l = console.log async.series [ (callback) -> l 'Series 1' callback null, 1 (callback) -> l 'Series 2' callback null, 2 (callback) -> l 'Series 3' callback null, 3 ], (err, results) -> throw err if err? l 'Finished ' + JSON.stringify results # * prints # Series 1 # Series 2 # Series 3 # Finished [1,2,3]
簡単
async = require 'async' l = console.log someMethod = -> async.waterfall [ (callback) -> len = 1 l 'waterfall ' + len callback null, len + 1 (len, callback) -> l 'waterfall ' + len callback null, len + 1 (len, callback) -> l 'waterfall ' + len callback null, len + 1 ], (err, results) -> throw err if err? l 'waterfall finished ' + results async.series [ (callback) -> l 'series 1' someMethod() callback null, 1 , (callback) -> l 'series 2' callback null, 2 ], (err, results) -> throw err if err? l 'series finished ' + JSON.stringify results # * ideal prints # series 1 # waterfall 1 # waterfall 2 # waterfall 3 # waterfall finished 4 # series 2 # series finished [1,2] # * real prints # series 1 # series 2 # series finished [1,2] # waterfall 1 # waterfall 2 # waterfall 3 # waterfall finished 4
アルェ?
というのも、 async.series さんは同期的に、 async.waterfall さんはどうやら非同期に事を済ますらしく、 someMethod で何か処理をしてから次の series に行きたいなって時でも、 waterfall さんはよろしくない動きをしてしまう。
中身を読むと、どうやらwaterfallの各メソッドは setImmediate を使って後からやってねって形で呼ばれているみたいなので、仕方ない。
# ... someMethod = (parentCallback) -> # ... ], (err, results) -> l 'waterfall finished ' + results parentCallback err, 1 if typeof parentCallback is 'function' async.series [ (callback) -> l 'series 1' someMethod callback , (callback) -> # ... # * prints # series 1 # waterfall 1 # waterfall 2 # waterfall 3 # waterfall finished 4 # series 2 # series finished [1,2]
という風に親元の callback を引数で渡してあげて、 waterfall の最終処理の callback 内で呼んであげるという手法で一応予想通りの順番で動いたわけだが、どうも納得がいかない...。もっとうまいことできないかな?
そもそも状態が残りまくっててキモイので理想的な書き方からは程遠いはずです。なので、「seriesとwaterfallには同期と非同期の差があるんだな」くらいの感覚でとらえてください。