はじめに
Node.jsを使ってリスト順にファイル処理などを実装したかった
しかしNode.jsはnon-blocking処理を行うため,実装の仕方によっては意図しない順序で処理が実行される恐れがある.
なので明示的に順次処理を記述してやる必要がある.
今回はnpmのパッケージの一つであるasyncを使った順次処理を実装した
なお,掲載しているスクリプトはCoffeeScriptからJSにツールによって変換されたものです,完全な動作保証は行いません
実行環境
- Node.js v0.12.2
非同期処理の落とし穴
私は非同期処理でファイル処理を実装しようとして落とし穴にハマりました.
ファイル初期化よりファイル書き込みが先行してしまったり,ファイル読み込み前にファイル書き込みが走ってしまったり…
詳しくは↓ブログにて,非同期処理と格闘している方が居ましたのでそちらを参照されたし.
非同期よ、決着をつけようじゃないか!(rororo1989のブログ)
参考文献にも載せますが,色々な方が同期処理の実装を書いていらっしゃいます.
私はasyncを使って,わかりやすくお手軽な実装が出来ないかと模索して,その結果を載せようと思い,記事にしました.
async.serise() + setTimeout()
async.series([
function(callback) {
console.log('proc1');
//処理1
//…
setTimeout(callback, 1000);
}, function(callback) {
console.log('proc2');
//処理2
//…
setTimeout(callback, 1000);
}, function(callback) {
return console.log('処理終了');
}
], function(err, results) {
if (err) {
return console.log('err[' + err + ']');
}
});
処理の流れとしては
* 処理1を実行
* コールバックを1000ms後に呼び出し→次の処理が呼び出される
* 処理2を実行
* コールバックを1000ms後に呼び出し→次の処理が呼び出される
という形です.これで簡単な順次処理は簡潔に記述できます.
ただし,処理する対象の数だけ関数を記述必要があります.
ファイルリストを渡して順番に処理するといったことはこの形では不可能です.
asyncforEach() + setTimeOut()
var list = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
async.forEachSeries(list, (function(item, callback) {
console.log(item);
//繰り返し処理
//…
setTimeout(callback, 1000);
}), function(err) {
if (err) {
throw err;
}
//処理終了
return console.log("end");
});
処理の流れとしては
- リストからitemを一つ選択
- 処理実行
- setTimeoutで1000ms後に処理呼び出し
- すべてのitem実行後終了
というような感じ.これでfor文も同期処理に実行されるようになる.
疑問
上記処理だと,setTimeOutによって処理を制御している.なのでsetTimeOutの秒数で処理が実行される.処理の終了時間が判明すれば,処理を続けざまに行うことで完全な順次実行ができる.おそらくPromiseあたりを使えば実装できそう?asyncの中にまたasyncを入れて,中のasyncの最後にcallback呼び出しすれば大丈夫?