JavaScript事件循環(huán)及宏任務(wù)微任務(wù)原理解析
首先看一段代碼:

打印順序是什么?
正確答案:script start, script end, promise1, promise2, setTimeout
其中涉及到事件循環(huán)(event loop),宏任務(wù)(macrotask),微任務(wù)(microtask)
一、事件循環(huán) Event Loop
程序中設(shè)置兩個(gè)線程:一個(gè)負(fù)責(zé)程序本身的運(yùn)行,稱為"主線程";另一個(gè)負(fù)責(zé)主線程與其他進(jìn)程(主要是各種I/O操作)的通信,被稱為"Event Loop線程"(可以譯為"消息線程")。
所有任務(wù)可以分成兩種,一種是同步任務(wù)(synchronous),另一種是異步任務(wù)(asynchronous)。
同步任務(wù)指的是,在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù);
異步任務(wù)指的是,不進(jìn)入主線程、而進(jìn)入"任務(wù)隊(duì)列"(task queue)的任務(wù),只有"任務(wù)隊(duì)列"通知主線程,某個(gè)異步任務(wù)可以執(zhí)行了,該任務(wù)才會(huì)進(jìn)入主線程執(zhí)行。
一般而言,異步任務(wù)有以下三種類型:
1、普通事件,如click、resize等

2、資源加載,如load、error等

3、定時(shí)器,包括setInterval、setTimeout等

事件循環(huán)具體過程就是:
- 同步任務(wù)進(jìn)入主線程,異步任務(wù)進(jìn)入Event Table并注冊(cè)函數(shù)。
- 當(dāng)異步任務(wù)完成時(shí),Event Table會(huì)將這個(gè)函數(shù)移入Event Queue。
- 主線程內(nèi)的任務(wù)執(zhí)行完畢執(zhí)行棧為空,會(huì)去Event Queue讀取對(duì)應(yīng)的函數(shù),進(jìn)入主線程執(zhí)行。
- 上述過程會(huì)不斷重復(fù),也就是常說的Event Loop(事件循環(huán))。
二、宏任務(wù)與微任務(wù)
在JavaScript中,任務(wù)被分為兩種,一種宏任務(wù)(MacroTask),一種叫微任務(wù)(MicroTask)。
2.1MacroTask(宏任務(wù))
宿主環(huán)境提供的(瀏覽器和node)
script全部代碼、setTimeout、setInterval。
瀏覽器為了能夠使得JS內(nèi)部task與DOM任務(wù)能夠有序的執(zhí)行,會(huì)在一個(gè)task執(zhí)行結(jié)束后,在下一個(gè) task 執(zhí)行開始前,對(duì)頁(yè)面進(jìn)行重新渲染 (task->渲染->task->...)
2.2MicroTask(微任務(wù))
語言標(biāo)準(zhǔn)提供的
Promise、await
async函數(shù)表示函數(shù)里面可能會(huì)有異步方法,await后面跟一個(gè)表達(dá)式,async方法執(zhí)行時(shí),遇到await會(huì)立即執(zhí)行表達(dá)式,然后把a(bǔ)wait表達(dá)式后面的代碼放到微任務(wù)隊(duì)列里,讓出執(zhí)行棧讓同步代碼先執(zhí)行
async function foo() {
var a = await new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 2000);
});
console.log(a); // 第2秒時(shí)輸出: 1
}
foo();
2.3宏任務(wù)與微任務(wù)執(zhí)行順序:
- 執(zhí)行棧在執(zhí)行完同步任務(wù)后,查看執(zhí)行棧是否為空,如果執(zhí)行棧為空,就會(huì)去檢查微任務(wù)隊(duì)列是否為空,如果為空的話,就執(zhí)行宏任務(wù),否則就一次性執(zhí)行完所有微任務(wù)。
- 每次單個(gè)宏任務(wù)執(zhí)行完畢后,檢查微任務(wù)隊(duì)列是否為空,如果不為空的話,會(huì)按照先入先出的規(guī)則全部執(zhí)行完微任務(wù)后,設(shè)置微任務(wù)隊(duì)列為null,然后再執(zhí)行宏任務(wù),如此循環(huán)。
總結(jié):同步—>微任務(wù)—>宏任務(wù)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 淺談JavaScript宏任務(wù)和微任務(wù)執(zhí)行順序
- 淺談js中的宏任務(wù)和微任務(wù)
- JavaScript中的宏任務(wù)和微任務(wù)執(zhí)行順序
- JavaScript宏任務(wù)和微任務(wù)區(qū)別介紹
- JS事件循環(huán)機(jī)制event loop宏任務(wù)微任務(wù)原理解析
- JavaScript?微任務(wù)和宏任務(wù)講解
- 詳解JS事件循環(huán)及宏任務(wù)微任務(wù)的原理
- 淺談javascript事件環(huán)微任務(wù)和宏任務(wù)隊(duì)列原理
- JavaScript中的宏任務(wù)和微任務(wù)詳情
- JavaScript的宏任務(wù)和微任務(wù)有哪些以及怎樣執(zhí)行的詳解
相關(guān)文章
JS 滾動(dòng)事件window.onscroll與position:fixed寫兼容IE6的回到頂部組件
這篇文章主要介紹了JS 滾動(dòng)事件window.onscroll與position:fixed寫兼容IE6的回到頂部組件的相關(guān)資料,需要的朋友可以參考下2016-10-10
JavaScript實(shí)現(xiàn)的使用鍵盤控制人物走動(dòng)實(shí)例
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的使用鍵盤控制人物走動(dòng)實(shí)例,也可說是一個(gè)JS實(shí)現(xiàn)的小人走動(dòng)小游戲,需要的朋友可以參考下2014-08-08
JS實(shí)現(xiàn)定時(shí)任務(wù)每隔N秒請(qǐng)求后臺(tái)setInterval定時(shí)和ajax請(qǐng)求問題
這篇文章主要介紹了JS實(shí)現(xiàn)定時(shí)任務(wù)每隔N秒請(qǐng)求后臺(tái)setInterval定時(shí)和ajax請(qǐng)求 的相關(guān)資料,需要的朋友可以參考下2017-10-10
javascript獲取當(dāng)前鼠標(biāo)坐標(biāo)的方法
這篇文章主要介紹了javascript獲取當(dāng)前鼠標(biāo)坐標(biāo)的方法,可針對(duì)不同瀏覽器獲取鼠標(biāo)的坐標(biāo)位置,是非常實(shí)用技巧,需要的朋友可以參考下2015-01-01
JavaScript ES6 Class類實(shí)現(xiàn)原理詳解
這篇文章主要介紹了JavaScript ES6 Class類實(shí)現(xiàn)原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
JavaScript?中URL?查詢字符串(query?string)的序列與反序列化的方法
在 JavaScript 中,可以使用?URLSearchParams?對(duì)象來處理 URL 中的查詢字符串,這篇文章主要介紹了JavaScript?中URL查詢字符串(query?string)的序列與反序列化,需要的朋友可以參考下2023-01-01
javascript獲取設(shè)置div的高度和寬度兼容任何瀏覽器
Javascript如何獲取和設(shè)置div的高度和寬度,并且兼容任何瀏覽器,感興趣的朋友不妨看看下面的代碼或許有意想不到的收獲2013-09-09

