亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

理清瀏覽器下的事件循環(huán)機(jī)制(Event Loop)

nemo / 3093人閱讀

摘要:何為事件循環(huán)機(jī)制的任務(wù)分兩種,分別是同步任務(wù)和異步任務(wù)。如上圖所示主線程在執(zhí)行代碼的時(shí)候,遇到異步任務(wù)進(jìn)入并注冊(cè)回調(diào)函數(shù),有了運(yùn)行結(jié)果后將它添加到事件隊(duì)列中,然后繼續(xù)執(zhí)行下面的代碼,直到同步代碼執(zhí)行完。

我們知道,JavaScript作為瀏覽器的腳本語言,起初是為了與用戶交互和操作DOM,為了避免因?yàn)橥瑫r(shí)操作了同一DOM節(jié)點(diǎn)而引起沖突,被設(shè)計(jì)成為一種單線程語言。

而單線程語言最大的特性就是同一時(shí)間只能做一件事,這個(gè)任務(wù)未完成下一個(gè)任務(wù)就要等待,這樣無疑是對(duì)資源的極大浪費(fèi),而且嚴(yán)重時(shí)會(huì)引起阻塞,造成用戶體驗(yàn)極差。這個(gè)時(shí)候就引出了異步的概念,而異步的核心就是事件循環(huán)機(jī)制Event Loop。

何為事件循環(huán)機(jī)制?

JavaScript的任務(wù)分兩種,分別是同步任務(wù)和異步任務(wù)。

同步任務(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í)行。

如上圖所示:

主線程在執(zhí)行代碼的時(shí)候,遇到異步任務(wù)進(jìn)入Event Table并注冊(cè)回調(diào)函數(shù),有了運(yùn)行結(jié)果后將它添加到事件隊(duì)列(callback queue)中,然后繼續(xù)執(zhí)行下面的代碼,直到同步代碼執(zhí)行完。

主線程執(zhí)行完同步代碼后,讀取callback queue中的任務(wù),如果有可執(zhí)行任務(wù)則進(jìn)入主線程執(zhí)行

不斷重復(fù)以上步驟,就形成了事件循環(huán)(Event Loop)

結(jié)合上面步驟分析下這個(gè)例子:

1. 執(zhí)行主線程同步任務(wù),輸出start【1】,繼續(xù)往下執(zhí)行
2. 遇到setTimeout,進(jìn)入event table注冊(cè)setTimeout回調(diào),setTimeout回調(diào)執(zhí)行完后,繼續(xù)往下執(zhí)行
3. 輸出end【2】,同步任務(wù)執(zhí)行完畢
4. 進(jìn)入event queue,檢查是否有可執(zhí)行任務(wù),取出event queue中setTimeout任務(wù)開始執(zhí)行,輸出setTimeout【3】

結(jié)果依次為:start -> end -> setTimeout

瀏覽器環(huán)境下的異步任務(wù)
在瀏覽器和node中的事件循環(huán)與執(zhí)行機(jī)制是不同的,要注意區(qū)分,不要搞混。
執(zhí)行過程

瀏覽器環(huán)境的異步任務(wù)分為宏任務(wù)(macroTask)和微任務(wù)(microtask),當(dāng)滿足條件時(shí)會(huì)分別被放進(jìn)宏任務(wù)隊(duì)列和微任務(wù)隊(duì)列(先進(jìn)先出),等待被執(zhí)行。

微任務(wù):
promise,MutationObserver

宏任務(wù):
script整體,setTimeout & setIntervat,I/O,UI render。

執(zhí)行過程如下:

如圖所示:

1. 把整體的script代碼作為宏任務(wù)執(zhí)行
2. 執(zhí)行過程中如果遇到宏任務(wù)和微任務(wù),滿足條件時(shí)分別添加至宏任務(wù)隊(duì)列和微任務(wù)隊(duì)列
3. 執(zhí)行完一個(gè)宏任務(wù)后,取出所有微任務(wù)依次執(zhí)行,如果微任務(wù)一直有新的被添加進(jìn)來,則一直執(zhí)行,直到把微任務(wù)隊(duì)列清空
4. 不斷重復(fù)2和3,直到所有任務(wù)被清空,結(jié)束執(zhí)行。

分析:

第一輪:

輸出start【1】,將setTimeout回調(diào)函數(shù)@1,放進(jìn)宏任務(wù)隊(duì)列;

將setTimeout回調(diào)函數(shù)@2,放進(jìn)宏任務(wù)隊(duì)列;

將setTimeout回調(diào)函數(shù)@3,放進(jìn)宏任務(wù)隊(duì)列;

執(zhí)行new Promise函數(shù)輸出promise4【2】,將Promise.then@1放進(jìn)微任務(wù)隊(duì)列;

輸出end【3】,此時(shí)隊(duì)列如下所示:

第一輪宏任務(wù)執(zhí)行完畢,開始執(zhí)行微任務(wù),取出微任務(wù)Promise.then@1,輸出promise5【4】,此時(shí)微任務(wù)隊(duì)列被清空,開始第二輪執(zhí)行。

第二輪:

取出宏任務(wù)setTimeout回調(diào)函數(shù)@1,輸出timer1【5】,將回調(diào)函數(shù)中的Promise.then@2放進(jìn)微任務(wù)隊(duì)列;

宏任務(wù)setTimeout回調(diào)函數(shù)@1中無宏任務(wù),開始執(zhí)行微任務(wù),取出Promise.then@2,輸出promise1【6】,此時(shí):

setTimeout回調(diào)函數(shù)@1中宏任務(wù)隊(duì)列和微任務(wù)隊(duì)列均被清空,開始第三輪執(zhí)行

第三輪:

取出宏任務(wù)setTimeout回調(diào)函數(shù)@2,輸出timer2【7】,將Promise.then@3放進(jìn)微任務(wù)隊(duì)列;

setTimeout回調(diào)函數(shù)@2中無宏任務(wù),開始執(zhí)行微任務(wù),取出Promise.then@3,輸出promise2【8】,此時(shí):

宏任務(wù)setTimeout回調(diào)函數(shù)@2中宏任務(wù)隊(duì)列和微任務(wù)隊(duì)列均被清空,開始第四輪執(zhí)行

第四輪:

取出宏任務(wù)setTimeout回調(diào)函數(shù)@3,輸出timer3【9】,將Promise.then@4放進(jìn)微任務(wù)隊(duì)列;

setTimeout回調(diào)函數(shù)@3中無宏任務(wù),開始執(zhí)行微任務(wù),取出Promise.then@4,輸出promise3【10】

現(xiàn)在宏任務(wù)對(duì)列和微任務(wù)隊(duì)列都被清空了,完成執(zhí)行,結(jié)果為:start > promise4 > end > promise5 > timer1 > promise1 > timer2 > promise2 > timer3 > promise3

引入 async/await

asnyc知識(shí)點(diǎn)傳送門

await表達(dá)式的運(yùn)算結(jié)果取決于它右側(cè)的結(jié)果

當(dāng)遇到await時(shí),會(huì)阻塞函數(shù)體內(nèi)部處于await后面的代碼,跳出去執(zhí)行該函數(shù)外部的同步代碼,當(dāng)外部同步代碼執(zhí)行完畢,再回到該函數(shù)內(nèi)部執(zhí)行剩余的代碼

補(bǔ)充aynsc的一點(diǎn)知識(shí):

如果aynsc函數(shù)中return一個(gè)直接量,async 會(huì)把這個(gè)直接量通過Promise.resolve()封裝成Promise對(duì)象,如果什么都沒return,會(huì)被封裝成Promise.resolve(undefined)

那么 引入了async await之后的執(zhí)行過程是怎樣的呢?

分析:

第一輪:

執(zhí)行同步代碼,輸出:script start【1】,將setTimeout回調(diào)@1放入宏任務(wù)隊(duì)列;

進(jìn)入aynsc1函數(shù)中,執(zhí)行同步代碼輸出:async1 start【2】,遇到await從右向左執(zhí)行,進(jìn)入async2函數(shù),輸出:async2【3】;aynsc2函數(shù)體中未返回任何東西等價(jià)于返回了Promise.resolve(undefined),拿到返回值后進(jìn)入aynsc1函數(shù)體中,繼續(xù)執(zhí)行剩下的部分,這時(shí)候aynsc1中注釋部分等價(jià)于:

async function async1() {
  console.log("async1 start");
  //await async2();
  //console.log("async1 end");
   await new Promise((resolve) => resolve()).then(resolve => {
     console.log("async1 end")
   })
}

將Promise.then@1推入到微任務(wù)隊(duì)列;

繼續(xù)執(zhí)行同步代碼,輸出:promise1【4】,將Promise.then@2推入微任務(wù)隊(duì)列

繼續(xù)執(zhí)行同步代碼,輸出:script end【5】,第一輪宏隊(duì)列任務(wù)執(zhí)行完畢,此時(shí)如下:

開始執(zhí)行微任務(wù),取出微任務(wù)Promise.then@1,值為undefined,這個(gè)時(shí)候Promise.then@1完成執(zhí)行,則await aynsc2()得到了值也完成了執(zhí)行,不再阻塞后面代碼,那么執(zhí)行同步代碼輸出:async1 end【6】;

取出微任務(wù)Promise.then@2,輸出:promise2【7】,微任務(wù)全部執(zhí)行完畢,現(xiàn)在開始第二輪執(zhí)行

第二輪:

取出宏任務(wù)隊(duì)列中的setTimeout@1,輸出setTimeout【8】

所有任務(wù)隊(duì)列均為空,結(jié)束執(zhí)行,輸出結(jié)果為:script start > async1 start > async2 > promise1 > script end > async1 end > promise2 > setTimeout

補(bǔ)充谷歌瀏覽器測(cè)試結(jié)果:

借用一個(gè)例子:await一個(gè)直接值的情況

分析:

第一輪:

執(zhí)行同步函數(shù),輸出:1【1】,進(jìn)入async1函數(shù)中,輸出:2【2】,這個(gè)時(shí)候await雖然接收了一個(gè)直接值,但是還是要先執(zhí)行外邊的同步代碼之后才能執(zhí)行await后邊的值

繼續(xù)執(zhí)行同步代碼,輸出:3【3】,進(jìn)入Promise函數(shù),輸出:4【4】,將Promise.then推入微任務(wù)隊(duì)列

同步代碼執(zhí)行完畢,進(jìn)入 async1函數(shù)中輸出:5【5】

宏任務(wù)執(zhí)行完畢,進(jìn)入微任務(wù)隊(duì)列,開始執(zhí)行微任務(wù);取出Promise.then,輸出:6【6】

任務(wù)隊(duì)列為空,執(zhí)行完畢,結(jié)果為: 1 > 2 > 3 > 4 > 5 > 6

再借個(gè)例子,這個(gè)有點(diǎn)復(fù)雜

分析:

第一輪:

將setTimeOut@1放入宏任務(wù)列隊(duì);

執(zhí)行async1()函數(shù)體內(nèi)的函數(shù),輸出:1【1】,遇到await,進(jìn)入aynsc2函數(shù)體,輸出:2【2】,將該函數(shù)體內(nèi)promise.then@1放入微任務(wù)隊(duì)列中;

執(zhí)行New promise .. 輸出3【3】,將該函數(shù)體內(nèi)Promise.then@2放入微任務(wù)隊(duì)列中,第一輪宏任務(wù)執(zhí)行完畢,此時(shí):

開始執(zhí)行第一輪微任務(wù),取出Promise.then@1,輸出:4【4】,此時(shí)async2函數(shù)執(zhí)行完畢,進(jìn)入aynsc1函數(shù),此時(shí)改動(dòng)下aynsc1函數(shù),等價(jià)于:

async function async1() {
  console.log("1")
  //const data = await async2()
  //console.log("6")
   const data = await new Promise(resolve => resolve("async2的結(jié)果")).then((resolve) => {
                    console.log(6); 
                    return resolve;
                })

   return data;
}

將上面promise.then@3推入微任務(wù)隊(duì)列中,此時(shí):

接著執(zhí)行微任務(wù),取出promise.then@2,輸出:5【5】,取出promise.then@3,輸出:6【6】,此時(shí)函數(shù)async1執(zhí)行完成,接著執(zhí)行async1().then(...),將async1().then@1推到微任務(wù)隊(duì)列中,取出async1().then@1,輸出:7【7】和 "async2的結(jié)果"【8】;

第一輪任務(wù)執(zhí)行完畢,開始執(zhí)行第二輪,此時(shí):

第二輪:

開始執(zhí)行第二輪宏任務(wù),將setTimeOut@1取出執(zhí)行,輸出8【9】,完畢。

所以任務(wù)被執(zhí)行完畢,結(jié)果為:1 > 2 > 3 > 4 > 5 > 6 > 7 > async2的結(jié)果 > 8

------------------------ END ----------------------------

PS: 好記性不如爛筆頭,看了那么多資料,還是想總結(jié)一下,不然過一陣子就忘記了,如果辛苦指出哦,謝謝~

參考資料:

理解 JavaScript 的 async/await
瀏覽器和Node不同的事件循環(huán)(Event Loop)
Event Loop 原來是這么回事
這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制
從event loop到async await來了解事件循環(huán)機(jī)制
...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/102424.html

相關(guān)文章

  • 10分鐘理解JS引擎的執(zhí)行機(jī)制

    摘要:深入理解引擎的執(zhí)行機(jī)制靈魂三問為什么是單線程的為什么需要異步單線程又是如何實(shí)現(xiàn)異步的呢中的中的說說首先請(qǐng)牢記點(diǎn)是單線程語言的是的執(zhí)行機(jī)制。 深入理解JS引擎的執(zhí)行機(jī)制 1.靈魂三問 : JS為什么是單線程的? 為什么需要異步? 單線程又是如何實(shí)現(xiàn)異步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.說說setTimeout 首先,請(qǐng)牢記2...

    zzbo 評(píng)論0 收藏0
  • JavaScript Event Loop 機(jī)制詳解與 Vue.js 中實(shí)踐應(yīng)用

    摘要:機(jī)制詳解與中實(shí)踐應(yīng)用歸納于筆者的現(xiàn)代開發(fā)語法基礎(chǔ)與實(shí)踐技巧系列文章。事件循環(huán)機(jī)制詳解與實(shí)踐應(yīng)用是典型的單線程單并發(fā)語言,即表示在同一時(shí)間片內(nèi)其只能執(zhí)行單個(gè)任務(wù)或者部分代碼片。 JavaScript Event Loop 機(jī)制詳解與 Vue.js 中實(shí)踐應(yīng)用歸納于筆者的現(xiàn)代 JavaScript 開發(fā):語法基礎(chǔ)與實(shí)踐技巧系列文章。本文依次介紹了函數(shù)調(diào)用棧、MacroTask 與 Micr...

    livem 評(píng)論0 收藏0
  • JavaScript 運(yùn)行機(jī)制--Event Loop詳解

    摘要:上代碼代碼可以看出,不僅函數(shù)比指定的回調(diào)函數(shù)先執(zhí)行,而且函數(shù)也比先執(zhí)行。這是因?yàn)楹笠粋€(gè)事件進(jìn)入的時(shí)候,事件環(huán)可能處于不同的階段導(dǎo)致結(jié)果的不確定。這是因?yàn)橐驗(yàn)閳?zhí)行完后,程序設(shè)定了和,因此階段不會(huì)被阻塞進(jìn)而進(jìn)入階段先執(zhí)行,后進(jìn)入階段執(zhí)行。 JavaScript(簡(jiǎn)稱JS)是前端的首要研究語言,要想真正理解JavaScript就繞不開他的運(yùn)行機(jī)制--Event Loop(事件環(huán)) JS是一門...

    snifes 評(píng)論0 收藏0
  • 覽器和Node中的事件循環(huán)機(jī)制

    摘要:二瀏覽器端在講解事件循環(huán)之前先談?wù)勚型酱a異步代碼的執(zhí)行流程。三端我自己認(rèn)為的事件循環(huán)和瀏覽器端還是有點(diǎn)區(qū)別的,它的事件循環(huán)依靠引擎。四總結(jié)本篇主要介紹了瀏覽器和對(duì)于事件循環(huán)機(jī)制實(shí)現(xiàn),由于能力水平有限,其中可能有誤之處歡迎指出。 一、前言 前幾天聽公司一個(gè)公司三年的前端說今天又學(xué)到了一個(gè)知識(shí)點(diǎn)-微任務(wù)、宏任務(wù),我問他這是什么東西,由于在吃飯他淺淺的說了下,當(dāng)時(shí)沒太理解就私下學(xué)習(xí)整理一...

    KevinYan 評(píng)論0 收藏0
  • 覽器下的 Event Loop

    摘要:前言是以單線程的形式運(yùn)行在宿主環(huán)境下,采用了回調(diào)的形式來解決異步任務(wù)。線程中步就是在瀏覽器下的。 前言 javascript 是以單線程的形式運(yùn)行在宿主環(huán)境下,javascript 采用了回調(diào)的形式來解決異步任務(wù)。 為什么是單線程? javascript 的最開始的出現(xiàn)是為了給 web 頁(yè)面增添一些動(dòng)態(tài)的效果,那么就避免不了獲取頁(yè)面上的元素信息,如果 javascript 是以多線程的...

    forrest23 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

nemo

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<