読者です 読者をやめる 読者になる 読者になる

process.nextTick()その壱

Node.jsにてアプリを書いてれば、いずれは巡り会ったのだろうprocess.nextTick()とは、今朝の関西行きの新幹線車中で出会いました。結論から言って、0.10.xでは0.8.xから仕様が変わってるみたいなので添付ドキュメントを読んで実験っと。実行Node.jsのバージョンは、0.10.18です。

//app.js
setTimeout(function() {
    console.log('====Timeout.====');
}, 0);

var counter = 0;
process.maxTickDepth = 10;
process.nextTick(function f() {
    console.log('nextTick [%d]', ++counter);
    process.nextTick(f);
});

こんなコードの実行結果は以下。

$ node app.js
nextTick [1]
nextTick [2]
nextTick [3]
nextTick [4]
nextTick [5]
nextTick [6]
nextTick [7]
nextTick [8]
nextTick [9]
nextTick [10]
(node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.
...膨大な数、同じメッセージを繰り返し...
(node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.

RangeError: Maximum call stack size exceeded

おや?なんだこの膨大な数(なぜか565回)の警告は...。process.maxTickDepthが期待どおりに呼び出し深度はコントロールしてくれているのに、なぜにその後にRangeError?期待はnextTickを10回呼んでるうちどこかで、おそらく最後に、setTimeoutが1度呼ばれるのだけど。
リカーシブなprocess.nextTick()をコメントアウトすると、こちらは期待通りに以下の様子。

nextTick [1]
====Timeout.====

まあ、nextTickの再帰呼び出しは次バージョンで廃止だよんって警告されちょるから、それはそれでやらなきゃいいだけだが、気持ち悪い。

追記

こうしたら、Errorでなくなった。気持ち悪い!

//app.js
setTimeout(function() {
    console.log('====Timeout.====');
}, 0);

var counter = 0;
//process.maxTickDepth = 10;
process.nextTick(function f() {
    console.log('nextTick [%d]', ++counter);
    if(counter < 100) {
        process.nextTick(f);
    }
});

process.maxTickDepthが漠然と期待した動きを完全にはこなしていない。すくなくとも0.10.18では。