瀏覽器中 JS 的事件循環機制


目錄

  • 事件循環機制
  • 宏任務與微任務
  • 實例分析
  • 參考

1.事件循環機制

瀏覽器事件循環機制

瀏覽器執行JS代碼大致可以分為三個步驟,而這三個步驟的往復構成了JS的事件循環機制(如圖)。

第一步:主線程(JS引擎線程)中執行JS整體代碼或回調函數(也就是宏任務),執行過程中會將對象存儲到堆(heap)中,將函數的參數和局部變量加入到棧(stack)中,執行完畢后會釋放堆或退出棧。執行完這個宏任務后,會判斷微任務隊列(microtask queue)是否為空,如果不為空,則會將所有的微任務依次取出並執行。如果在這個過程中觸發了任何 Web APIs 將進行第二步操作。

第二步:調用 Web API,並在合適的時候將回調函數加入到事件回調隊列(event queue)中。比如執行了setTimeout(callback1, 1000),會創建一個計時器,並且在另一個線程(瀏覽器定時觸發線程)里面監聽計時器是否過期,等到計時器過期后,會將對應回調 callback1加入事件回調隊列中。

第三步:等到第一步中的微任務執行完畢之后,會判斷事件回調隊列(event queue)是否為空。如果不為空,則會取出並執行最先進入隊列的回調函數,執行過程如同第一步。如果為空,則會視情況進行等待或掛起主線程。


補充說明:瀏覽器的內核是多線程的,常駐線程有瀏覽器 GUI 渲染線程、JavaScript 引擎線程、瀏覽器定時觸發器線程、瀏覽器事件觸發線程、瀏覽器 http 異步請求線程。


2.宏任務與微任務

宏任務(macrotask):script(整體代碼)、setTimeout/setInterval、I/O、UI rendering等

微任務(microtask):Promise、MutationObserver等


JS代碼執行過程——宏任務與微任務的執行示意圖:

宏任務與微任務的執行示意圖

如圖,可以看出JS執行過程中,是先執行一個宏任務,再執行這個宏任務產生的對應微任務,執行完畢后,再執行后面的宏任務,以此往復。


3.實例分析

使用瀏覽器:Chrome Version 80.0.3987.163

第一組:

比較 setTimeout 與 Promise

console.log('start')

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

Promise.resolve().then(() => {
  console.log('microtask: promise')
})

console.log('end')

結果:

比較 setTimeout 與 Promise

分析:

以JS的事件循環機制來分析。首先,script(整體代碼)算是一個宏任務,執行完畢,會先后輸出"start"和"end",然后執行這個過程中產生的微任務,即promis.then中的回調,輸出"microtask: promise";這個過程中也調用了 Web API 中的 setTimeout,會創建一個計時器,過期后將回調添加到事件回調隊列中;然后再執行回調(第二個宏任務),輸出"setTimeout"。與瀏覽器運行輸出一致,符合預期。


第二組:

宏任務與微任務的執行順序對比

function func1() {
  console.log('func1')
  Promise.resolve().then(() => {
    console.log('microtask.promise1')
  })
}

function func2() {
  console.log('func2')
  Promise.resolve().then(() => {
    console.log('microtask.promise2')
  })
}

function main() {
  func1()
  func2()
  setTimeout(func1, 0);
  setTimeout(func2, 0);
}

main()

結果:

宏任務與微任務的執行順序對比

分析:

從輸出結果可以看出,當一個宏任務執行完畢后,會接着執行相應的所有微任務,執行完畢后,再執行后續的宏任務,並以往復,與預期相符。


4.參考

並發模型與事件循環

Javascript event loop

JavaScript Event Loop Explained

HTML系列:macrotask和microtask

【翻譯】Promises/A+規范


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM