Event Loop、 巨集任務和微任務

不得不愛xxy發表於2020-05-25

本文將介紹我自己對JS Event Loop巨集任務、微任務的理解。
二話不說先上圖:

接下來將會針對此圖講解什麼是Event Loop 什麼事巨集任務和微任務(其實聰明的你們通過圖大體也能瞭解的是吧~),再此之前先簡單介紹幾個概念。

為何js是單執行緒

JavaScript的單執行緒,與它的用途有關。作為瀏覽器指令碼語言,JavaScript的主要用途是與使用者互動,以及操作DOM。這決定了它只能是單執行緒,否則會帶來很複雜的同步問題。比如,假定JavaScript同時有兩個執行緒,一個執行緒在某個DOM節點上新增內容,另一個執行緒刪除了這個節點,這時瀏覽器應該以哪個執行緒為準?

所以,為了避免複雜性,從一誕生,JavaScript就是單執行緒,這已經成了這門語言的核心特徵,將來也不會改變。

為了利用多核CPU的計算能力,HTML5提出 Web Worker 標準,允許JavaScript指令碼建立多個執行緒,但是子執行緒完全受主執行緒控制,且不得操作DOM。所以,這個新標準並沒有改變JavaScript單執行緒的本質。(此段來自阮老師)

概念

  • 同步任務:在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務。
  • 非同步任務:不進入主執行緒、而進入任務佇列(Task Queue)的任務。
  • 任務佇列:是一個事件的佇列(也可以理解成訊息的佇列),IO裝置完成一項任務,就在"任務佇列"中新增一個事件,表示相關的非同步任務可以進入"執行棧"了。主執行緒讀取"任務佇列",就是讀取裡面有哪些事件。

詳解圖示

  1. 當一段程式碼在主執行緒執行時,會有同步任務和非同步任務,非同步任務會判斷是微任務還是巨集任務,進行不同處理。然後繼續執行當前主執行緒內的程式碼,直到結束。此段主執行緒執行的的為巨集任務
  2. 接著上面的判斷,巨集任務的非同步操作會先進入Event Table執行,然後當執行結束會把回撥函式推入到Event Queue ,然後等待主執行緒的結束。對於微任務的非同步會推入到另外一個Event Queue ,等待主執行緒的結束。
  3. 當主執行緒結束後,先執行所有的微任務,然後執行把巨集任務的任務佇列(Event Queue)中的event拉到主執行緒執行。
  4. 一直迴圈前面的操作。至此你應該懂的EventLoop了。
    備註:如果在執行 microtask(微任務) 的過程中,又產生了microtask,那麼會加入到佇列的末尾,也會在這個週期被呼叫執行。

舉個例子?

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

new Promise(function(resolve) {
  console.log('promise 1');
  resolve();
  console.log('promise 2')
}).then(function() {
    console.log('promise then');
})

console.log('1');

輸出結果:promise 1 、promise 2 、1 、promise then 、setTimeout
解釋

  • 這段程式碼作為巨集任務,進入主執行緒。
  • 先遇到setTimeout,則進入Event Table執行並註冊,然後將其回撥函式發到巨集任務Event Queue。
  • 接下來遇到了Promise,new Promise立即執行,then函式分發到微任務Event Queue。裡面的console.log(),立即執行。
  • 繼續,遇到console.log(),立即執行。
  • 至此這個主執行緒的巨集任務執行結束,接著查詢微任務,發現then的回撥然後執行。
  • 第一輪事件迴圈結束了,我們開始第二輪迴圈,從巨集任務Event Queue開始執行。即巨集任務Event Queue中setTimeout對應的回撥函式,立即執行。
  • END。

為何會有巨集任務和微任務的說法。

eventloop中處理微任務和巨集任務的邏輯也是不同廠商按照規範實現的 jsvm。

補充幾個巨集任務和微任務

巨集任務 瀏覽器 Node
setTimeout
setInterval
setImmediate x
requestAnimationFrame x
微任務 瀏覽器 Node
process.nextTick x
MutationObserver x
Promise.then catch finally

來自我的簡書的文章:Event Loop、 巨集任務和微任務

相關文章