面試官:說說對 Node-js 中的事件循環機制理解?

一、是什麼

瀏覽器事件循環中,我們瞭解到javascript在瀏覽器中的事件循環機制,其是根據HTML5定義的規範來實現

而在NodeJS中,事件循環是基於libuv實現,libuv是一個多平臺的專注於異步 IO 的庫,如下圖最右側所示:

上圖EVENT_QUEUE 給人看起來只有一個隊列,但EventLoop存在 6 個階段,每個階段都有對應的一個先進先出的回調隊列

二、流程

上節講到事件循環分成了六個階段,對應如下:

每個階段對應一個隊列,當事件循環進入某個階段時, 將會在該階段內執行回調,直到隊列耗盡或者回調的最大數量已執行, 那麼將進入下一個處理階段

除了上述 6 個階段,還存在process.nextTick,其不屬於事件循環的任何一個階段,它屬於該階段與下階段之間的過渡, 即本階段執行結束, 進入下一個階段前, 所要執行的回調,類似插隊

流程圖如下所示:

Node中,同樣存在宏任務和微任務,與瀏覽器中的事件循環相似

微任務對應有:

宏任務對應有:

其執行順序爲:

三、題目

通過上面的學習,下面開始看看題目

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}

async function async2() {
    console.log('async2')
}

console.log('script start')

setTimeout(function () {
    console.log('setTimeout0')
}, 0)

setTimeout(function () {
    console.log('setTimeout2')
}, 300)

setImmediate(() => console.log('setImmediate'));

process.nextTick(() => console.log('nextTick1'));

async1();

process.nextTick(() => console.log('nextTick2'));

new Promise(function (resolve) {
    console.log('promise1')
    resolve();
    console.log('promise2')
}).then(function () {
    console.log('promise3')
})

console.log('script end')

分析過程:

執行結果如下:

script start
async1 start
async2
promise1
promise2
script end
nextTick1
nextTick2
async1 end
promise3
setTimeout0
setImmediate
setTimeout2

最後有一道是關於setTimeoutsetImmediate的輸出順序

setTimeout(() ={
  console.log("setTimeout");
}, 0);

setImmediate(() ={
  console.log("setImmediate");
});

輸出情況如下:

情況一:
setTimeout
setImmediate

情況二:
setImmediate
setTimeout

分析下流程:

這裏的關鍵在於這 1ms,如果同步代碼執行時間較長,進入Event Loop的時候 1 毫秒已經過了,setTimeout先執行,如果 1 毫秒還沒到,就先執行了setImmediate

參考文獻

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/7Mp-dfiT_ZcviqJkUKCS_Q