細說setTimeout/setImmediate/process.nextTick的區別

node.js中的非IO的異步API提供了四種方法,分別爲setTimeOut(),setInterval(),setImmediate()以及process.nextTick(),四種方法實現原理類似,但達到的效果略有區別:javascript

1、事件循環Event Loop

首先,咱們須要瞭解node.js的基於事件循環的事件模型,正是由於它才使得node.js中回調函數十分廣泛,也正是基於此,node.js實現了單線程高效的異步IO(這裏說的單線程主要說的是執行javascript代碼部分的線程,而異步IO部分node.js其實仍是利用線程池去執行的)。css

簡單的講就是,在node.js啓動時,建立了一個相似while(true)的循環體,每次執行一次循環體稱爲一次tick,每一個tick的過程就是查看是否有事件等待處理,若是有,則取出事件極其相關的回調函數並執行,而後執行下一次tick。因此,有以下代碼:java

A(); B(); C();
  • 1
  • 2
  • 3

它的執行邏輯是,先詢問事件觀察者當前是否有任務須要執行?觀察者回答「有」,因而取出A執行,A是否有回調函數?若是有(若是沒有則繼續詢問當前是否有任務須要執行),則取出回調函數並執行(注意:回調函數的執行基本都是異步的,可能不止一個回調),執行完回調後經過某種方式通知調用者,我執行完了,並把執行結果給你,你本身酌情處理吧,主函數不須要不斷詢問回調函數執行結果,回調函數會以通知的方式告知調用者我執行完了(don’t call me ,i will call you.),而這個過程主線程並不須要等待回調函數執行完成,它會繼續向前執行,即再次詢問觀察者當前是否還有任務須要執行,重複上面的步驟。。。直到觀察者回答沒有了,線程結束。node

整個事件循環的邏輯以下圖:異步

這裏寫圖片描述

二:setTimeOut(),setInterval(),setImmediate()以及process.nextTik()

這裏面setTimeOut()與setInterval()除了執行頻次外基本相同,都表示主線程執行完必定時間後當即執行,而setImmediate()與之十分類似,也表示主線程執行完成後當即執行。那麼他們之間的區別是什麼呢?函數

代碼以下:oop

setTimeout(function(){ console.log("setTimeout"); },0); setImmediate(function(){ console.log("setImmediate"); });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

二者都表明主線程完成後當即執行,其執行結果是不肯定的,多是setTimeout回調函數執行結果在前,也多是setImmediate回調函數執行結果在前,但setTimeout回調函數執行結果在前的機率更大些,這是由於他們採用的觀察者不一樣,setTimeout採用的是相似IO觀察者,setImmediate採用的是check觀察者,而process.nextTick()採用的是idle觀察者。spa

三種觀察者的優先級順序是:idle觀察者>>io觀察者>check觀察者線程

process.nextTick()與setImmediate()和setTimeout()的區別以下:code

一、原始代碼:

A(); B(); C();
  • 1
  • 2
  • 3

它的執行順序即代碼順序:

這裏寫圖片描述

二、process.nextTick()執行效果,代碼以下:

A(); process.nextTick(B); C();
  • 1
  • 2
  • 3

它的執行順序以下:

這裏寫圖片描述

三、setImmediate()或者setTimeout()執行效果,代碼以下:

A(); setImmediate(B);//或者setTimeout(B,0); C();
  • 1
  • 2
  • 3

它的執行順序以下:

這裏寫圖片描述

結論: process.nextTick(),效率最高,消費資源小,但會阻塞CPU的後續調用; setTimeout(),精確度不高,可能有延遲執行的狀況發生,且由於動用了紅黑樹,因此消耗資源大; setImmediate(),消耗的資源小,也不會形成阻塞,但效率也是最低的。

相關文章
相關標籤/搜索