JavaScript在瀏覽器環境下的事件迴圈(Event Loop)

影子同學發表於2019-04-09
這裡主要記錄在日常中對知識的學習,通過結合筆記與自身理解的方式嘗試寫下總結
文章對細節可能不會一一介紹解釋,內容僅作參考
複製程式碼

一、背景

  1. JavaScript是一門單執行緒語言
  2. 單執行緒所帶來的任務執行方式

二、同步任務與非同步任務

  單執行緒就意味著,所有的任務都需要排隊,當前一個任務結束時,才會執行後一個任務。如果前一個任務耗時很長,後一個任務就不得不一直等待。 如果是因為計算量大,CPU忙不過來倒也正常,但是很多時候CPU是閒著的,因為IO裝置(輸入輸出裝置)很慢(比如Ajax操作從網路讀取資料),不得不等著結果出來,再往下執行。

  這時主執行緒完全可以不管IO裝置,掛起處於等待中的任務,先執行排在後面的任務。等到IO裝置返回了結果,再回過頭,把掛起的任務繼續執行下去。於是,所有任務可以分成兩種:

  1. 同步任務
  2. 非同步任務

  在這裡用一張圖來說明:

JavaScript在瀏覽器環境下的事件迴圈(Event Loop)

  • 同步和非同步任務分別進入不同的執行"場所",同步的進入主執行緒,非同步的進入Event Table
  • 當非同步任務完成時,Event Table會將對應的回撥移入Event Queue中
  • JS引擎會持續不斷檢查主執行緒執行棧是否為空,當主執行緒內的任務全部執行完畢後,會去Event Queue讀取排頭第一個,進入到主執行緒執行
  • 上述過程不斷重複,形成事件迴圈(Event Loop)

三、巨集任務與微任務

  除了廣義的同步任務和非同步任務,會對任務有更精細的定義:

  • 巨集任務:整體程式碼、setTimeout、setInterval
  • 微任務:Promise

  不同型別的任務會進入對應的Event Queue,比如setTimeout和setInterval會進入相同的Event Queue

  第一次進入整體程式碼(巨集任務)後,開始第一遍迴圈,在主執行緒任務全部執行完畢後,會先去讀取所有的微任務進行執行,然後再到巨集任務,而巨集任務裡面或許又包含著巨集任務與微任務。以此不斷迴圈執行

  用一張圖說明:

JavaScript在瀏覽器環境下的事件迴圈(Event Loop)

  舉個栗子

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

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

console.log('console')
複製程式碼
  • 這段程式碼會作為巨集任務,進入主執行緒
  • 先遇到setTimeout,將其放入Event Table,完成後會將其回撥函式註冊並放入到巨集任務Event Queue
  • 接下來遇到了Promise,new Promise立即執行,然後遇到console.log('promise'),立即執行。then函式放入微任務Event Queue。
  • 遇到console.log('console'),立即執行
  • 整體程式碼作為第一個巨集任務執行結束,接著檢視是否有微任務?我們發現了then在微任務Event Queue裡面,執行
  • 微任務全部執行完畢,第一輪事件迴圈結束,開始第二輪迴圈。從巨集任務Event Queue發現有setTimeout對應的回撥函式(多個巨集任務的時候取隊頭),立即執行
  • 檢查無可執行任務,結束

相關文章