Node.js Event loop 監控器。高的 frequency 和低的持續時間是最理想的 event loop 狀態。
上圖顯示三點半到五點半之間,event loop 的 frequency 驟降,然後 duration 居高不下。
Node.js 是一個基於事件的平台。 這意味着在 Node 中發生的一切都是對事件的反應。通過 Node 的事務會遍歷級聯的回調(a cascade of callbacks)。
這一切都由一個名為 libuv 的庫處理,它提供了一種稱為事件循環的機制。
關於 Node.js 的事件循環,有很多誤解。
誤解1:事件循環機制運行在獨立於用户邏輯的單獨線程內
誤解:
有一個主線程,用户的 JavaScript 代碼(userland 代碼)在其中運行,另一個主線程運行事件循環。 每次發生異步操作時,主線程都會將工作交給事件循環線程,一旦完成,事件循環線程就會通知主線程執行回調。
正確的理解:
只有一個線程執行 JavaScript 代碼,這是運行事件循環的線程。 回調的執行(運行中的 Node.js 應用程序中的每個用户空間代碼都是回調)由事件循環完成。
誤解2:異步操作通過線程池完成
異步操作,如使用文件系統、執行出站 HTTP 請求或與數據庫對話,總是加載到 libuv 提供的線程池中。
正確的理解:
Libuv 默認創建一個包含四個線程的線程池來卸載異步工作。 今天的操作系統已經為許多 I/O 任務提供了異步接口(例如 Linux 上的 AIO)。
只要有可能,libuv 就會使用那些異步接口,避免使用線程池。
這同樣適用於第三方子系統,如數據庫。 這裏驅動程序的作者寧願使用異步接口也不願使用線程池。
簡而言之:只有在沒有其他辦法的情況下,才會使用線程池進行異步I/O.
誤解3:Event Loop 利用了棧或者隊列的數據結構
事件循環不斷遍歷異步任務的 FIFO,並在任務完成時執行回調。
正確的理解:
雖然涉及到類似隊列的結構,但事件循環不會遍歷並處理堆棧。 作為一個進程的事件循環是一組具有特定任務的階段,這些階段以循環方式處理。