![](/img/trans.png)
[英]Why use process.nextTick to ensure correct execution of asynchronous tasks?
[英]Why does process.nextTick() trigger a TypeError in this “fake asynchronous function”, but setTimeout() doesn't?
注意:我在Node.js上運行了這段代碼
我正在制作一個假的“非阻塞”函數,所以我可以理解如何為Node.js編寫異步函數。 這樣做的時候,我遇到了一個我不太了解的場景。
下面有一個“假”異步函數的代碼,該函數帶有一個回調函數和一個計數器。 該函數將遞歸調用自身[counter]次,然后執行提供的回調函數。 每10次迭代,它將控制權釋放回事件隊列。
原始劇本
//fakeCounter helps us keep track of whether or not the operation is "complete"
//fn is the callback function that will be executed when the operation is complete
function asyncOp(fn, fakeCounter){
//if fakeCounter is less than or equal to zero, that means the
//operation is "complete" and you can call the callback now
if(fakeCounter <= 0) return fn();
console.log("another [" + fakeCounter + "] cycles to go");
//every 10 or so iterations, release control
if(fakeCounter % 10 === 0){
process.nextTick(asyncOp(fn,--fakeCounter));
}else{
asyncOp(fn,--fakeCounter);
}
}
asyncOp(function (){
console.log("operation complete");
}, 10000);
如上所示,我可以通過使用process.nextTick來釋放控件。 但是,當我執行腳本時,出現以下錯誤:
原始結果
another [10000] cycles to go
another [9999] cycles to go
another [9989] cycles to go
...
another [3] cycles to go
another [2] cycles to go
another [1] cycles to go
operation complete
node.js:415
callback();
^
TypeError: undefined is not a function
at process._tickCallback (node.js:415:13)
at Function.Module.runMain (module.js:499:11)
at startup (node.js:119:16)
at node.js:902:3
此錯誤和堆棧跟蹤對我來說幾乎沒有意義,因此我被撓了一下頭。
但是,當我修改asyncOp函數以使其通過setTimeout釋放控制權時,不會出現此類錯誤:
修改功能
function asyncOp(fn, fakeCounter){
if(fakeCounter <= 0) return fn();
console.log("another [" + fakeCounter + "] cycles to go");
if(fakeCounter % 10 === 0){
setTimeout(asyncOp(fn, --fakeCounter)); //<-- see here
}else{
asyncOp(fn,--fakeCounter);
}
}
修改結果
...
another [3] cycles to go
another [2] cycles to go
another [1] cycles to go
operation complete
而且沒有任何錯誤發生。
...因此,我的問題是:為什么使用process.nextTick()引發TypeError,而使用setTimeout()卻沒有呢? 為什么首先要引發TypeError?
編輯:
如果將來有人在讀這個,正確的答案(如下面提到的@ m02ph3u5)是將函數調用包裝在匿名函數中:
if(fakeCounter % 10 === 0){
process.nextTick(function(){asyncOp(fn, --fakeCounter)}).
}else{
asyncOp(fn,--fakeCounter);
}
但是,在此特定示例中,最好使用setImmediate而不是process.nextTick,因為顯然遞歸的process.nextTick調用將在下一版本的node.js中中斷。 此外,在這種情況下使用process.nextTick()將導致RangeError。 因此,正確的解決方案是使用以下方法:
if(fakeCounter % 10 === 0){
setImmediate(function (){
asyncOp(fn,--fakeCounter)
});
}else{
asyncOp(fn,--fakeCounter);
}
謝謝@ m02ph3u5和@mscdex
原因是process.nextTick()
期望將函數作為第一個參數,而asyncOp()
返回undefined
(默認情況下)。 undefined
不是一個函數,因此會引發TypeError
。 setTimeout()
當前不會立即檢查其第一個參數的類型(但是這將在節點v6中更改),因此這就是它不會引發錯誤的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.