您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Javascript的Event Loop怎么實(shí)現(xiàn)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Javascript的Event Loop怎么實(shí)現(xiàn)”吧!
單線程意味著我們的js
代碼只能從上往下同步執(zhí)行,同一時(shí)間只能執(zhí)行一個(gè)任務(wù),這會(huì)導(dǎo)致某些執(zhí)行時(shí)間較長(zhǎng)或者執(zhí)行時(shí)間不確定的任務(wù)會(huì)卡住其它任務(wù)的正常執(zhí)行,Event Loop
出現(xiàn)的原因正是為了解決此問(wèn)題。
為了解決上述的排隊(duì)問(wèn)題,有了任務(wù)隊(duì)列,瀏覽器在異步任務(wù)有了結(jié)果后,將其添加到任務(wù)隊(duì)列,以待將來(lái)執(zhí)行,其他任務(wù)就在主線程上同步執(zhí)行。
這里要注意的是,向任務(wù)隊(duì)列中添加任務(wù)的時(shí)機(jī)是異步任務(wù)有結(jié)果后。其實(shí)任務(wù)隊(duì)列中存在的就是異步任務(wù)的回調(diào)函數(shù)。
Js程序中的同步任務(wù)是指在主線程中執(zhí)行的任務(wù),異步任務(wù)是指進(jìn)入任務(wù)隊(duì)列中的任務(wù)
所有的同步任務(wù)都在主線程上執(zhí)行,行成一個(gè)執(zhí)行棧。當(dāng)主線程上任務(wù)執(zhí)行完畢后,從任務(wù)隊(duì)列中取出任務(wù)執(zhí)行。
var name = "zhouwei"; setTimeout(() => { console.log(1); }, 1000); console.log(name);
上面代碼在瀏覽器中執(zhí)行如下,我們將程序全局執(zhí)行環(huán)境的代碼理解為包裹在一個(gè)main函數(shù)中的代碼,這段代碼的執(zhí)行棧變化如下圖:
開(kāi)始執(zhí)行代碼,將main
任務(wù)(全局代碼入棧執(zhí)行),當(dāng)遇到異步任務(wù)(setTimeout
后)。
瀏覽器接管異步任務(wù),并在1s后將異步任務(wù)的結(jié)果(回調(diào)函數(shù))添加到任務(wù)隊(duì)列。
執(zhí)行棧中的同步任務(wù)執(zhí)行完畢,此時(shí)任務(wù)隊(duì)列為空(未到1s),執(zhí)行棧也為空
異步任務(wù)有結(jié)果后,首先進(jìn)入任務(wù)隊(duì)列排隊(duì)(因?yàn)榭赡苡泻芏喈惒饺蝿?wù))。
執(zhí)行棧從任務(wù)隊(duì)列中取出任務(wù)開(kāi)始同步執(zhí)行。
重復(fù)執(zhí)行第5步。
Js執(zhí)行棧不斷的從任務(wù)隊(duì)列中讀取任務(wù)并執(zhí)行的過(guò)程就是Event Loop
我們知道任務(wù)隊(duì)列中存放的是異步任務(wù)的結(jié)果,那么異步任務(wù)都有哪些了?
1、事件
Javascript
中的事件有很多,都是屬于異步任務(wù)。由瀏覽器接管,當(dāng)事件觸發(fā)時(shí),將事件的回調(diào)加入的任務(wù)隊(duì)列中,在Js執(zhí)行棧中沒(méi)有任務(wù)時(shí)執(zhí)行。
2、Http請(qǐng)求
3、定時(shí)器
4、requestAnimationFrame等
宏任務(wù)(macrotask
)和微任務(wù)(microtask
)
在了解了任務(wù)隊(duì)列和Event Loop
后,我們知道了Js執(zhí)行棧從任務(wù)隊(duì)列中讀取任務(wù)執(zhí)行,但這個(gè)具體工程我們?nèi)蝿?wù)不清楚,這里引出了宏任務(wù)和微任務(wù)的的概念,幫助我們理解Event Loop。
進(jìn)入任務(wù)隊(duì)列中的異步任務(wù)回調(diào)分為了宏任務(wù)和微任務(wù), Js執(zhí)行棧執(zhí)行宏任務(wù)和微任務(wù)的規(guī)則如下圖所示。
Js執(zhí)行棧首先執(zhí)行一個(gè)宏任務(wù)(全局代碼) -> 從任務(wù)隊(duì)列中讀取所有微任務(wù)執(zhí)行 -> UI rendering(瀏覽器渲染界面) -> 從任務(wù)隊(duì)列讀取一個(gè)宏任務(wù) -> 所有微任務(wù) -> UI rendering -> …
在每一輪的Event Loop結(jié)束后(1個(gè)宏任務(wù) + 所有微任務(wù)),瀏覽器開(kāi)始渲染界面(如果有需要渲染的UI,否則不執(zhí)行UI rendering),在
UI rendering
結(jié)束后,開(kāi)始下一輪Event Loop。
哪些是宏任務(wù)?
setTimeout
setInterval
setImmediate (Node)
requestAnimationFrame (瀏覽器)
I/O (事件回調(diào))
UI rendering (瀏覽器渲染)
哪些是微任務(wù)?
Promise
process.nextTick (Node)
MutationObserver (現(xiàn)代瀏覽器提供的用來(lái)檢測(cè) DOM 變化的網(wǎng)頁(yè)接口)
setTimeout延時(shí)問(wèn)題
一般來(lái)說(shuō)在代碼中setTimeout
中回調(diào)的執(zhí)行時(shí)間都是大于設(shè)置的時(shí)間。 這是因?yàn)樵?code>setTimeout指定時(shí)間到達(dá)后,雖然回調(diào)函數(shù)被添加到了任務(wù)隊(duì)列,但是此時(shí)Js執(zhí)行棧中可能有正在執(zhí)行的任務(wù),此回調(diào)需要等待Js執(zhí)行棧的任務(wù)執(zhí)行完畢后才有機(jī)會(huì)執(zhí)行,這就是setTimeout
延時(shí)問(wèn)題。
練習(xí)下下方代碼輸出結(jié)果吧:
console.log(1); setTimeout(() => { console.log(2); Promise.resolve().then(() => { console.log(3) }); }); new Promise(resolve => { console.log(4); setTimeout(() => { console.log(5); }); resolve(6) }).then(data => { console.log(data); }) setTimeout(() => { console.log(7); }) console.log(8);
用上方的我們說(shuō)過(guò)的js執(zhí)行機(jī)制來(lái)分析這道題:
1: 執(zhí)行全局任務(wù)中的同步代碼輸出:
1
4
8
這里需要注意的是Promise
接受的handle
函數(shù)是同步任務(wù),而then
方法是異步任務(wù),所以會(huì)直接輸出4。
2: 這時(shí)的任務(wù)隊(duì)列中有三個(gè)setTimeout
的宏任務(wù),和一個(gè)Promise
的微任務(wù)
// 此時(shí)的宏任務(wù)是 setTimeout(() => { console.log(2); Promise.resolve().then(() => { console.log(3) }); }); setTimeout(() => { console.log(5); }); setTimeout(() => { console.log(7); }) // 此時(shí)微任務(wù)是 then(data => { console.log(data); })
執(zhí)行一個(gè)微任務(wù), 輸出:6
3: 接著執(zhí)行第一個(gè)宏任務(wù)
setTimeout(() => { console.log(2); Promise.resolve().then(() => { console.log(3) }); });
輸出:2
在此宏任務(wù)中,向任務(wù) 隊(duì)列添加了一個(gè)微任務(wù)。此時(shí)任務(wù)隊(duì)列有了新的微任務(wù)。
4:執(zhí)行一個(gè)微任務(wù),輸出:3
then(() => { console.log(3) });
5: 繼續(xù)按照規(guī)則執(zhí)行任務(wù), 輸出: 5、7
整體輸出情況是:
1、4、8、6、2、3、5、7
到此,相信大家對(duì)“Javascript的Event Loop怎么實(shí)現(xiàn)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。