|
什么是事件循環(huán)?想要了解什么是事件循環(huán)就要從js的工作原理開(kāi)始說(shuō)起: JS主要的特點(diǎn)就是單線(xiàn)程,所謂單線(xiàn)程就是進(jìn)程中只有一個(gè)線(xiàn)程在運(yùn)行。 為什么JS是單線(xiàn)程的而不是多線(xiàn)程的呢? JS的主要用途就是與用戶(hù)交互,操作DOM,假設(shè)JS同時(shí)有兩個(gè)線(xiàn)程,一個(gè)線(xiàn)程中在某個(gè)DOM節(jié)點(diǎn)上添加或者修改內(nèi)容,而另一個(gè)線(xiàn)程在這個(gè)DOM節(jié)點(diǎn)上執(zhí)行刪除該節(jié)點(diǎn)操作,這樣就會(huì)產(chǎn)生沖突。 單線(xiàn)程就意味著所有任務(wù)都需要排隊(duì),前一任務(wù)結(jié)束,才會(huì)執(zhí)行后一個(gè)任務(wù),當(dāng)是如果當(dāng)遇到前一個(gè)任務(wù)耗時(shí)很長(zhǎng)的情況,后一個(gè)任務(wù)就不得不一直等著。因此,就有了同步任務(wù)、異步任務(wù)。 同步任務(wù)和異步任務(wù)在js中是如何執(zhí)行的呢? js的代碼運(yùn)行會(huì)形成一個(gè)主線(xiàn)程和一個(gè)任務(wù)隊(duì)列。主線(xiàn)程會(huì)自上而下依次執(zhí)行我們的js代碼,形成一個(gè)執(zhí)行棧。 同步任務(wù)就會(huì)被放到這個(gè)主線(xiàn)程中依次執(zhí)行。而異步任務(wù)被放入到任務(wù)隊(duì)列中執(zhí)行,執(zhí)行完就會(huì)在任務(wù)隊(duì)列中打一個(gè)標(biāo)記,形成一個(gè)對(duì)應(yīng)的事件。當(dāng)主線(xiàn)程中的任務(wù)全部運(yùn)行完畢,js會(huì)去提取并執(zhí)行任務(wù)隊(duì)列中的事件。這個(gè)過(guò)程是循環(huán)進(jìn)行的,這就是EventLoop。 JS引擎執(zhí)行異步代碼不用等待,是因?yàn)橛惺录?duì)列和事件循環(huán)。 事件循環(huán)是指主線(xiàn)程重復(fù)從事件隊(duì)列中取消息、執(zhí)行的過(guò)程。指整個(gè)執(zhí)行流程。 事件隊(duì)列是一個(gè)存儲(chǔ)著待執(zhí)行任務(wù)的序列,其中的任務(wù)嚴(yán)格按照時(shí)間先后順序執(zhí)行,排在隊(duì)頭的任務(wù)會(huì)率先執(zhí)行,而排在隊(duì)尾的任務(wù)會(huì)最后執(zhí)行。(即先進(jìn)先出)
事件隊(duì)列:
事件循環(huán)運(yùn)行機(jī)制 (1)執(zhí)行一個(gè)宏任務(wù)(棧中沒(méi)有就從事件隊(duì)列中獲?。?/p> (2)執(zhí)行過(guò)程中如果遇到微任務(wù),就將它添加到微任務(wù)的任務(wù)隊(duì)列中; (3)宏任務(wù)執(zhí)行完畢后,立即執(zhí)行當(dāng)前微任務(wù)隊(duì)列的所有微任務(wù); (4)當(dāng)前微任務(wù)執(zhí)行完畢,開(kāi)始檢查渲染,然后GUI線(xiàn)程接管渲染; (5)渲染完畢后,JS線(xiàn)程繼續(xù)接管,開(kāi)始下一個(gè)宏任務(wù)。
事例: async function async1() {
console.log("async1 start"); //(2)
await async2();
console.log("async1 end"); //(6)
}
async function async2() {
console.log( 'async2'); //(3)
}
console.log("script start"); //(1)
setTimeout(function () {
console.log("settimeout"); //(8)
},0);
async1();
new Promise(function (resolve) {
console.log("promise1"); //(4)
resolve();
}).then(function () {
console.log("promise2"); //(7)
});
console.log('script end');//(5)
按照事件循環(huán)機(jī)制分析以上代碼運(yùn)行流程: 1. 首先,事件循環(huán)從宏任務(wù)(macrotask)隊(duì)列開(kāi)始,首先讀取script(整體代碼)任務(wù);當(dāng)遇到任務(wù)源(task source)時(shí),則會(huì)先分發(fā)任務(wù)到對(duì)應(yīng)的任務(wù)隊(duì)列中去。 2. 然后我們看到首先定義了兩個(gè)async函數(shù),此時(shí)沒(méi)有調(diào)用,接著往下看,然后遇到了 `console` 語(yǔ)句,直接輸出 `script start`。輸出之后,script 任務(wù)繼續(xù)往下執(zhí)行,遇到 `setTimeout`,其作為一個(gè)宏任務(wù)源,則會(huì)先將其任務(wù)分發(fā)到對(duì)應(yīng)的任務(wù)隊(duì)列中。 3. script 任務(wù)繼續(xù)往下執(zhí)行,執(zhí)行了async1()函數(shù),async函數(shù)中在await之前的代碼是立即執(zhí)行的,所以會(huì)立即輸出`async1 start`。 4. script任務(wù)繼續(xù)往下執(zhí)行,遇到Promise實(shí)例。由于Promise中的函數(shù)是立即執(zhí)行的,而后續(xù)的 `.then` 則會(huì)被分發(fā)到 microtask 的 `Promise` 隊(duì)列中去。所以會(huì)先輸出 `promise1`,然后執(zhí)行 `resolve`,將 `promise2` 分配到對(duì)應(yīng)隊(duì)列。 5. script任務(wù)繼續(xù)往下執(zhí)行,輸出了 `script end`,至此,全局任務(wù)就執(zhí)行完畢了。 6. 第二輪循環(huán)依舊從宏任務(wù)隊(duì)列開(kāi)始。此時(shí)宏任務(wù)中只有一個(gè) `setTimeout`,取出直接輸出即可,至此整個(gè)流程結(jié)束。 |
|
|
來(lái)自: Coder編程 > 《待分類(lèi)》