面試官:說說你對 Js 事件循環機制的理解?

我們都知道 JavaScript 是單線程語言, 就是因爲單線程的特性,就不得不提 js 中的同步和異步

一、同步和異步

所謂單線程,無非就是同步隊列和異步隊列,js 代碼是自上向下執行的,在主線程中立即執行的就是同步任務,比如簡單的邏輯操作及函數,而異步任務不會立馬立馬執行,會挪步放到到異步隊列中,比如 ajax、promise、事件、計時器等等。

也就是先執行同步,主線程結束後再按照異步的順序再次執行。

二、時間循環(Event Loop)

Event Loop 是什麼?中文翻譯是事件循環,等待主線程中任務全部完成後,再回來把異步隊列中任務放到主程序中運行,這樣反覆的循環,就是事件循環。

先來看組代碼

console.log('開始111');
setTimeout(function() {
   console.log('setTimeout111');
}, 0);
Promise.resolve().then(function() {
   console.log('promise111');
}).then(function() {
   console.log('promise222');
});
console.log('開始222');

我們猜想一下上面的代碼,會怎樣打印?我們知道,肯定是先走同步的代碼,從上往下,先打印 “開始 111”,再打印 “開始 222”。
中途的三個異步,進入到了異步隊列,等待同步執行完(打印完),返回來再執行異步,所以是後打印出來。
打印的結果先放一放,我們稍後回來再說。現在我們中途插播一段知識點:

三、宏觀任務和微觀任務(先執行微觀任務,再執行宏觀任務)

在事件循環中,每進行一次循環操作稱爲 tick,tick 的任務處理模型是比較複雜的,裏邊有兩個詞:

分別是 Macro Task (宏任務)和 Micro Task(微任務)。

簡單來說:

宏觀任務主要包含:

setTimeout、setInterval、script(整體代碼)、I/O、UI 交互事件、setImmediate(Node.js 環境)

微觀任務主要包括:

Promise、MutaionObserver、process.nextTick(Node.js 環境)

規範:

先執行微觀任務,再執行宏觀任務

那麼我們知道了,Promise 屬於微觀任務, setTimeout、setInterval 屬於宏觀任務,先執行微觀任務,等微觀任務執行完,再執行宏觀任務。所以我們再看一下這個代碼:

console.log('開始111');

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

Promise.resolve().then(function() {
  console.log('promise111');
}).then(function() {
  console.log('promise222');
});

console.log('開始222');

我們按照步驟來分析下:

所以打印的順序爲:

開始 111 、開始 222 、 promise111 、 promise222 、 setTimeout111 。

同理,我們再來分析一個代碼:

console.log('開始111');

setTimeout(function () {
   console.log('timeout111');
});

new Promise(resolve ={
   console.log('promise111');
   resolve();
   setTimeout(() => console.log('timeout222'));
}).then(function () {
   console.log('promise222')
})

console.log('開始222');

分析一下:

所以,打印的順序爲:

開始 111 、 promise111 、 開始 222 、 promise222 、 timeout111 、 timeout222 .

先執行主任務,把異步任務放入循環隊列當中,等待主任務執行完,再執行隊列中的異步任務。異步任務先執行微觀任務,再執行宏觀任務。一直這樣循環,反覆執行,就是事件循環機制。

參考資料

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