node.js中的非IO的非同步API提供了四種方法,分別為setTimeOut()
,setInterval()
,setImmediate()
以及process.nextTick()
,四種方法實現原理相似,但達到的效果略有區別:
一、事件迴圈Event Loop
首先,我們需要了解node.js的基於事件迴圈的事件模型,正是因為它才使得node.js中回撥函式十分普遍,也正是基於此,node.js實現了單執行緒高效的非同步IO(這裡說的單執行緒主要說的是執行javascript程式碼部分的執行緒,而非同步IO部分node.js其實還是利用執行緒池去執行的)。
簡單的講就是,在node.js啟動時,建立了一個類似while(true)的迴圈體,每次執行一次迴圈體稱為一次tick,每個tick的過程就是檢視是否有事件等待處理,如果有,則取出事件極其相關的回撥函式並執行,然後執行下一次tick。所以,有如下程式碼:
A();
B();
C();
複製程式碼
它的執行邏輯是,先詢問事件觀察者當前是否有任務需要執行?觀察者回答“有”,於是取出A執行,A是否有回撥函式?如果有(如果沒有則繼續詢問當前是否有任務需要執行),則取出回撥函式並執行(注意:回撥函式的執行基本都是非同步的,可能不止一個回撥),執行完回撥後通過某種方式通知呼叫者,我執行完了,並把執行結果給你,你自己酌情處理吧,主函式不需要不斷詢問回撥函式執行結果,回撥函式會以通知的方式告知呼叫者我執行完了(don’t call me ,i will call you.),而這個過程主執行緒並不需要等待回撥函式執行完成,它會繼續向前執行,即再次詢問觀察者當前是否還有任務需要執行,重複上面的步驟。。。直到觀察者回答沒有了,執行緒結束。
整個事件迴圈的邏輯如下圖:
二、setTimeOut(),setInterval(),setImmediate()以及process.nextTik()
這裡面setTimeOut()與setInterval()除了執行頻次外基本相同,都表示主執行緒執行完一定時間後立即執行,而setImmediate()與之十分相似,也表示主執行緒執行完成後立即執行。那麼他們之間的區別是什麼呢?
程式碼如下:
setTimeout(function(){
console.log("setTimeout");
},0);
setImmediate(function(){
console.log("setImmediate");
});
複製程式碼
兩者都代表主執行緒完成後立即執行,其執行結果是不確定的,可能是setTimeout
回撥函式執行結果在前,也可能是setImmediate
回撥函式執行結果在前,但setTimeout
回撥函式執行結果在前的概率更大些,這是因為他們採用的觀察者不同,setTimeout
採用的是類似IO觀察者,setImmediate
採用的是check觀察者,而process.nextTick()
採用的是idle觀察者。
三種觀察者的優先順序順序是:idle觀察者>>io觀察者>check觀察者
process.nextTick()與setImmediate()和setTimeout()的區別如下:
1、原始程式碼:
A();
B();
C();
複製程式碼
它的執行順序即程式碼順序:
2、process.nextTick()執行效果,程式碼如下:A();
process.nextTick(B);
C();
複製程式碼
它的執行順序如下:
3、setImmediate()或者setTimeout()執行效果,程式碼如下:A();
setImmediate(B);//或者setTimeout(B,0);
C();
複製程式碼
它的執行順序如下:
結論:
process.nextTick()
,效率最高,消費資源小,但會阻塞CPU的後續呼叫;
setTimeout()
,精確度不高,可能有延遲執行的情況發生,且因為動用了紅黑樹,所以消耗資源大;
setImmediate()
,消耗的資源小,也不會造成阻塞,但效率也是最低的。
轉載https://blog.csdn.net/hkh_1012/article/details/53453138