2014年7月29日 星期二

[JS] nextTick() 介紹與應用


Node.js是單線程的,除了系統IO之外,在它的事件輪詢過程中,同一時間只會處理一個事件。你可以把事件輪詢想象成一個大的隊列,在每個時間點上,系統只會處理一個事件。即使你的電腦有多個CPU核心,你也無法同時並行的處理多個事件。但也就是這種特性使得node.js適合處理I/O型的應用,不適合那種CPU運算型的應用。在每個I/O型的應用中,你只需要給每一個輸入輸出定義一個回調函數即可,他們會自動加入到事件輪詢的處理隊列里。當I/O操作完成後,這個回調函數會被觸發。然後系統會繼續處理其他的請求。

在這種處理模式下,process.nextTick()的意思就是定義出一個動作,並且讓這個動作在下一個事件輪詢的時間點上執行。我們來看一個例子。例子中有一個foo(),你想在下一個時間點上調用他,可以這麽做:
function foo() {
    console.error('foo');
}
 
process.nextTick(foo);
console.error('bar');

執行結果將會是:
bar
foo

我們也可以使用setTimeout()函數來達到貌似同樣的執行效果:
setTimeout(foo, 0);
console.log('bar');

但在內部的處理機制上,process.nextTick()和setTimeout(fn, 0)是不同的,process.nextTick()不是一個單純的延時,他有更多的特性,這裡有兩者的效能比較
更精確的說,process.nextTick()定義的調用會創建一個新的子堆棧。在當前的棧里,你可以執行任意多的操作。但一旦調用netxTick,函數就必須返回到父堆棧。然後事件輪詢機制又重新等待處理新的事件,如果發現nextTick的調用,就會創建一個新的棧。


什麼時候會使用到 nextTick ?

因為JavaScript是單線程的Runtime,如果有需要長時間的運算,往往會卡死其他的程式,例如事件觸發的 function。
更多應用情境可以參考原出處

也可以參考Fred的這篇:探討 NODE.JS 的非同步機制