Node.js でバッチ処理プログラムを書くときなどに、ループ処理の中から非同期関数を呼び出すことがある。
素直にコードを書いてしまうと、複数スレッドから非同期関数を同時にコールするような感じになってしまう。その非同期関数がデータベースやネットワークなどのIO系だと、処理がたまってあふれてしまったりもする (データベース接続数が限界に達するとか)。これを解決するために、ループから何度も非同期関数を呼び出すときに、順番に関数を呼び出すよう同期的に処理をしたい。
今回は関数の再帰呼び出しによるループ処理を利用することで、非同期関数を同期させてコールするコードを書いてみた。
以下、4パターンのサンプルコードとその実行結果を置いておく。
- 普通のループ
- 再帰呼び出しによるループ
- 同期型関数をループ内から呼び出す
- 非同期型関数を再帰呼び出しによるループ内から呼び出す
普通のループ
まず、普通のループ処理を書いてみる。
$ cat loop.js
// loop by for statement
var i = 0; // counter for loop
var hoge = 0;
for(i=0; i<10; i++){
hoge += 2;
console.log('for: ' + hoge);
}
実行結果。
$ node loop.js
for: 2
for: 4
for: 6
for: 8
for: 10
for: 12
for: 14
for: 16
for: 18
for: 20
再帰呼び出しによるループ
再帰呼出しでループを実現してみる。
$ cat recursive.js
var i = 0; // counter for loop
var hoge = 0;
outputCounter();
// loop by recursive call
function outputCounter(){
if(i < 10){
hoge += 2;
console.log('recursive: ' + hoge);
i++;
outputCounter();
}
}
実行結果。
$ node recursive.js
recursive: 2
recursive: 4
recursive: 6
recursive: 8
recursive: 10
recursive: 12
recursive: 14
recursive: 16
recursive: 18
recursive: 20
同期型関数をループ内から呼び出す
同期型関数 sync_hoge をループから呼び出す処理を書いてみる。
$ cat sync_loop.js
// loop by for statement
var i = 0; // counter for loop
var hoge = 0;
// loop by for statement
for(i=0; i<10; i++){
console.log('i: ' + i);
hoge = sync_hoge(hoge);
console.log('hoge: ' + hoge);
}
function sync_hoge(hoge){
return hoge + 2;
}
実行結果。
$ node sync_loop.js
i: 0
hoge: 2
i: 1
hoge: 4
i: 2
hoge: 6
i: 3
hoge: 8
i: 4
hoge: 10
i: 5
hoge: 12
i: 6
hoge: 14
i: 7
hoge: 16
i: 8
hoge: 18
i: 9
hoge: 20
非同期型関数を再帰呼び出しによるループ内から呼び出す
非同期関数 async_hoge を再帰呼び出しによるループから呼び出す処理を書いてみる。
2つの関数が相互に呼び合う形になっている。
$ cat ./async_loop.js
var i = 0; // counter for loop
var hoge = 0;
myCallback(hoge);
// loop by recursive call
function myCallback(hoge){
if(i < 10){
console.log('i: ' + i);
i++; // countup before calling a function for a fast function
async_hoge(hoge, function(response){
console.log('hoge: ' + response);
myCallback(response);
});
}
}
function async_hoge(hoge, callback){
setTimeout(function(){
callback(hoge + 2);
}, 500);
}
実行結果。
$ node ./async_loop.js
i: 0
hoge: 2
i: 1
hoge: 4
i: 2
hoge: 6
i: 3
hoge: 8
i: 4
hoge: 10
i: 5
hoge: 12
i: 6
hoge: 14
i: 7
hoge: 16
i: 8
hoge: 18
i: 9
hoge: 20
非同期関数を順番に呼び出すだけなら、 Q などの Promise 系ライブラリを使ってコールバック地獄にならないよう、ある程度は綺麗に書ける。非同期関数を呼び出すループ処理も、ライブラリで綺麗に同期処理が書けるなら試してみたい。
tags: node.js javascript
Posted by NI-Lab. (@nilab)