【譯】Understanding NodeJS Event Loop
原文連結 Understanding NodeJS Event Loop
Event Loop
是個讓人頭大的知識點,今天我們先了解下Nodejs中的 Event Loop
(不要跟瀏覽器中的Event Loop混淆)。 在這篇文章中,作者將證明Node不完全是單執行緒的,並向你展示 事件迴圈
的一般實現。
快速瀏覽非阻塞I / O.
思考下這段程式碼:
const crypto = require('crypto') const start = Date.now() crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', () => { console.log('1:', Date.now() - start) }) //1: 1015 crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', () => { console.log('2:', Date.now() - start) }) //2: 1021 crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', () => { console.log('3:', Date.now() - start) }) //3: 1017 複製程式碼
當執行此程式碼時,所有函式呼叫都進入 事件迴圈
。執行程式碼之後,您會發現這3個函式呼叫所花費的時間幾乎相同。還記得 事件迴圈
在一個執行緒中嗎?Node是如何在一個執行緒內並行執行3個操作的?
Node基於C / C ++構建
我們上面觀察到的行為是因為Node實現了一個名為 libuv
的C模組。每當在事件迴圈中發生長時間執行的操作時, libuv
都會將該任務放入另一個執行緒中。操作結束後, 事件迴圈
將觸發回撥去處理結果。
現在,將 crypto.pbkdf2()
函式的呼叫次數增加到5次,看看會發生什麼。
您會發現前4個執行的時間幾乎相同,而最後一個執行則需要兩倍的時間。在這裡,我們遇到了一個 Node
的有趣部分。預設情況下, libuv庫
在稱為 “執行緒池”
的東西中啟動4個執行緒。並且這4個執行緒是並行執行的,這就是為什麼4個操作的時間是相同的。因為 執行緒池
一次只能執行4次操作,所以第五次操作只是等待先前的操作執行完成。這就是第五次操作需要更長時間的原因。
現在,我們來改變操作。這次我們將並行進行 http
呼叫,看看會發生什麼。
const https = require('https') const start = Date.now() function makeRequest() { https .request('https://www.baidu.com', res => { res.on('data', () => {}) res.on('end', () => { console.log(Date.now() - start) }) }) .end() } makeRequest() //67 makeRequest() //72 makeRequest() //72 makeRequest() //73 makeRequest() //74 複製程式碼
你會發現這5個的執行時間幾乎相同。我們可以合理地推斷出這些 http
呼叫既不會發生在單執行緒事件迴圈中,也不會發生在 執行緒池
中。所以發生了什麼事?
事實證明,一些底層任務(如 http請求
)被委託給作業系統 libuv
。這些任務在 事件迴圈
和 執行緒池
之外並行執行。
事件迴圈
還處理計時器事件,即 setTimeout
, setInterval
和 setImmediate
。註冊計時器事件時, 事件迴圈
將等待指定的時間並觸發回撥。
總之, 事件迴圈
歸結為這三種事件:
1.計時器事件,即 setTimeout
, setInterval
和 setImmediate
。
2.作業系統任務,例如伺服器監聽和 http
請求。
3.長時間執行的操作,例如 fs操作
和其他 Node API
。
這是一張圖表,用以說明:

感謝@serialcoder 大佬的指導。