本文將介紹我自己對JS Event Loop 和 宏任務(wù)、微任務(wù)的理解。
二話不說先上圖:

接下來將會針對此圖講解什么是Event Loop 什么事宏任務(wù)和微任務(wù)(其實聰明的你們通過圖大體也能了解的是吧~),再此之前先簡單介紹幾個概念。
為何js是單線程
JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節(jié)點上添加內(nèi)容,另一個線程刪除了這個節(jié)點,這時瀏覽器應(yīng)該以哪個線程為準?
所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成了這門語言的核心特征,將來也不會改變。
為了利用多核CPU的計算能力,HTML5提出 Web Worker 標準,允許JavaScript腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標準并沒有改變JavaScript單線程的本質(zhì)。(此段來自阮老師)
概念
- 同步任務(wù):在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù)。
-
異步任務(wù):不進入主線程、而進入
任務(wù)隊列(Task Queue)的任務(wù)。 - 任務(wù)隊列:是一個事件的隊列(也可以理解成消息的隊列),IO設(shè)備完成一項任務(wù),就在"任務(wù)隊列"中添加一個事件,表示相關(guān)的異步任務(wù)可以進入"執(zhí)行棧"了。主線程讀取"任務(wù)隊列",就是讀取里面有哪些事件。
詳解圖示
- 當一段代碼在主線程執(zhí)行時,會有同步任務(wù)和異步任務(wù),異步任務(wù)會判斷是微任務(wù)還是宏任務(wù),進行不同處理。然后繼續(xù)執(zhí)行當前主線程內(nèi)的代碼,直到結(jié)束。此段主線程執(zhí)行的的為宏任務(wù)。
- 接著上面的判斷,宏任務(wù)的異步操作會先進入
Event Table執(zhí)行,然后當執(zhí)行結(jié)束會把回調(diào)函數(shù)推入到Event Queue,然后等待主線程的結(jié)束。對于微任務(wù)的異步會推入到另外一個Event Queue,等待主線程的結(jié)束。 - 當主線程結(jié)束后,先執(zhí)行所有的微任務(wù),然后執(zhí)行把宏任務(wù)的任務(wù)隊列(
Event Queue)中的event拉到主線程執(zhí)行。 - 一直循環(huán)前面的操作。至此你應(yīng)該懂的
EventLoop了。
備注:如果在執(zhí)行 microtask(微任務(wù)) 的過程中,又產(chǎn)生了microtask,那么會加入到隊列的末尾,也會在這個周期被調(diào)用執(zhí)行。
舉個例子??
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');
輸出結(jié)果:promise 1 、promise 2 、1 、promise then 、setTimeout
解釋:
- 這段代碼作為宏任務(wù),進入主線程。
- 先遇到setTimeout,則進入Event Table執(zhí)行并注冊,然后將其回調(diào)函數(shù)發(fā)到宏任務(wù)Event Queue。
- 接下來遇到了Promise,new Promise立即執(zhí)行,then函數(shù)分發(fā)到微任務(wù)Event Queue。里面的console.log(),立即執(zhí)行。
- 繼續(xù),遇到console.log(),立即執(zhí)行。
- 至此這個主線程的宏任務(wù)執(zhí)行結(jié)束,接著查找微任務(wù),發(fā)現(xiàn)then的回調(diào)然后執(zhí)行。
- 第一輪事件循環(huán)結(jié)束了,我們開始第二輪循環(huán),從宏任務(wù)Event Queue開始執(zhí)行。即宏任務(wù)Event Queue中setTimeout對應(yīng)的回調(diào)函數(shù),立即執(zhí)行。
- END。
為何會有宏任務(wù)和微任務(wù)的說法。
eventloop中處理微任務(wù)和宏任務(wù)的邏輯也是不同廠商按照規(guī)范實現(xiàn)的 jsvm。
補充幾個宏任務(wù)和微任務(wù)
| 宏任務(wù) | 瀏覽器 | Node |
|---|---|---|
| setTimeout | √ | √ |
| setInterval | √ | √ |
| setImmediate | x | √ |
| requestAnimationFrame | √ | x |
| 微任務(wù) | 瀏覽器 | Node |
|---|---|---|
| process.nextTick | x | √ |
| MutationObserver | √ | x |
| Promise.then catch finally | √ | √ |