日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
圖解JavaScript事件循環(huán):微任務(wù)和宏任務(wù)

事件循環(huán):微任務(wù)和宏任務(wù)

創(chuàng)新互聯(lián)公司主營(yíng)曹縣網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,重慶APP開發(fā),曹縣h5微信小程序定制開發(fā)搭建,曹縣網(wǎng)站營(yíng)銷推廣歡迎曹縣等地區(qū)企業(yè)咨詢

瀏覽器中 JavaScript 的執(zhí)行流程和 Node.js 中的流程都是基于 事件循環(huán) 的。

理解事件循環(huán)的工作方式對(duì)于代碼優(yōu)化很重要,有時(shí)對(duì)于正確的架構(gòu)也很重要。

在本章中,我們首先介紹有關(guān)事件循環(huán)工作方式的理論細(xì)節(jié),然后介紹該知識(shí)的實(shí)際應(yīng)用。

事件循環(huán)

事件循環(huán) 的概念非常簡(jiǎn)單。它是一個(gè)在 JavaScript 引擎等待任務(wù),執(zhí)行任務(wù)和進(jìn)入休眠狀態(tài)等待更多任務(wù)這幾個(gè)狀態(tài)之間轉(zhuǎn)換的無限循環(huán)。

引擎的一般算法:

1.當(dāng)有任務(wù)時(shí):

  • 從最先進(jìn)入的任務(wù)開始執(zhí)行。

2.休眠直到出現(xiàn)任務(wù),然后轉(zhuǎn)到第 1 步。

當(dāng)我們?yōu)g覽一個(gè)網(wǎng)頁時(shí)就是上述這種形式。JavaScript 引擎大多數(shù)時(shí)候不執(zhí)行任何操作,它僅在腳本/處理程序/事件激活時(shí)執(zhí)行。

任務(wù)示例:

  • 當(dāng)外部腳本 
  • ……但是我們也可能想在任務(wù)執(zhí)行期間展示一些東西,例如進(jìn)度條。

    如果我們使用 setTimeout 將繁重的任務(wù)拆分成幾部分,那么變化就會(huì)被在它們之間繪制出來。

    這看起來更好看:

     
     
     
     
 
  •  
  •  
  • 現(xiàn)在 div 顯示了 i 的值的增長(zhǎng),這就是進(jìn)度條的一種。

    用例 3:在事件之后做一些事情

    在事件處理程序中,我們可能會(huì)決定推遲某些行為,直到事件冒泡并在所有級(jí)別上得到處理后。我們可以通過將該代碼包裝到零延遲的 setTimeout 中來做到這一點(diǎn)。

    在 創(chuàng)建自定義事件[1] 一章中,我們看到過這樣一個(gè)例子:自定義事件 menu-open 被在 setTimeout 中分派(dispatched),所以它在 click 事件被處理完成之后發(fā)生。

     
     
     
     
    1. menu.onclick = function() { 
    2.   // ... 
    3.  
    4.   // 創(chuàng)建一個(gè)具有被點(diǎn)擊的菜單項(xiàng)的數(shù)據(jù)的自定義事件 
    5.   let customEvent = new CustomEvent("menu-open", { 
    6.     bubbles: true 
    7.   }); 
    8.  
    9.   // 異步分派(dispatch)自定義事件 
    10.   setTimeout(() => menu.dispatchEvent(customEvent)); 
    11. }; 

    宏任務(wù)和微任務(wù)

    除了本章中所講的 宏任務(wù)(macrotask) 外,還有在 微任務(wù)隊(duì)列[2] 一章中提到的 微任務(wù)(microtask)。

    微任務(wù)僅來自于我們的代碼。它們通常是由 promise 創(chuàng)建的:對(duì) .then/catch/finally 處理程序的執(zhí)行會(huì)成為微任務(wù)。微任務(wù)也被用于 await 的“幕后”,因?yàn)樗?promise 處理的另一種形式。

    還有一個(gè)特殊的函數(shù) queueMicrotask(func),它對(duì) func 進(jìn)行排隊(duì),以在微任務(wù)隊(duì)列中執(zhí)行。

    每個(gè)宏任務(wù)之后,引擎會(huì)立即執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù),然后再執(zhí)行其他的宏任務(wù),或渲染,或進(jìn)行其他任何操作。

    例如,看看下面這個(gè)示例:

     
     
     
     
    1. setTimeout(() => alert("timeout")); 
    2.  
    3. Promise.resolve() 
    4.   .then(() => alert("promise")); 
    5.  
    6. alert("code"); 

    這里的執(zhí)行順序是怎樣的?

    1. code 首先顯示,因?yàn)樗浅R?guī)的同步調(diào)用。
    2. promise 第二個(gè)出現(xiàn),因?yàn)?then 會(huì)通過微任務(wù)隊(duì)列,并在當(dāng)前代碼之后執(zhí)行。
    3. timeout 最后顯示,因?yàn)樗且粋€(gè)宏任務(wù)。

    更詳細(xì)的事件循環(huán)圖示如下(順序是從上到下,即:首先是腳本,然后是微任務(wù),渲染等):

    微任務(wù)會(huì)在執(zhí)行任何其他事件處理,或渲染,或執(zhí)行任何其他宏任務(wù)之前完成。

    這很重要,因?yàn)樗_保了微任務(wù)之間的應(yīng)用程序環(huán)境基本相同(沒有鼠標(biāo)坐標(biāo)更改,沒有新的網(wǎng)絡(luò)數(shù)據(jù)等)。

    如果我們想要異步執(zhí)行(在當(dāng)前代碼之后)一個(gè)函數(shù),但是要在更改被渲染或新事件被處理之前執(zhí)行,那么我們可以使用 queueMicrotask 來對(duì)其進(jìn)行安排(schedule)。

    這是一個(gè)與前面那個(gè)例子類似的,帶有“計(jì)數(shù)進(jìn)度條”的示例,但是它使用了 queueMicrotask而不是 setTimeout。你可以看到它在最后才渲染。就像寫的是同步代碼一樣:

     
     
     
     
     
  •  
  •  
  • 總結(jié)

    更詳細(xì)的事件循環(huán)算法(盡管與 規(guī)范[3] 相比仍然是簡(jiǎn)化過的):

    1.從 宏任務(wù) 隊(duì)列(例如 "script")中出隊(duì)(dequeue)并執(zhí)行最早的任務(wù)。

    2.執(zhí)行所有 微任務(wù):

    • 出隊(duì)(dequeue)并執(zhí)行最早的微任務(wù)。
    • 當(dāng)微任務(wù)隊(duì)列非空時(shí):

    3.執(zhí)行渲染,如果有。

    4.如果宏任務(wù)隊(duì)列為空,則休眠直到出現(xiàn)宏任務(wù)。

    5.轉(zhuǎn)到步驟 1。

    安排(schedule)一個(gè)新的 宏任務(wù):

    • 使用零延遲的 setTimeout(f)。

    它可被用于將繁重的計(jì)算任務(wù)拆分成多個(gè)部分,以使瀏覽器能夠?qū)τ脩羰录鞒龇磻?yīng),并在任務(wù)的各部分之間顯示任務(wù)進(jìn)度。

    此外,也被用于在事件處理程序中,將一個(gè)行為(action)安排(schedule)在事件被完全處理(冒泡完成)后。

    安排一個(gè)新的 微任務(wù):

    • 使用 queueMicrotask(f)。
    • promise 處理程序也會(huì)通過微任務(wù)隊(duì)列。

    在微任務(wù)之間沒有 UI 或網(wǎng)絡(luò)事件的處理:它們一個(gè)立即接一個(gè)地執(zhí)行。

    所以,我們可以使用 queueMicrotask 來在保持環(huán)境狀態(tài)一致的情況下,異步地執(zhí)行一個(gè)函數(shù)。

    Web Workers:

    對(duì)于不應(yīng)該阻塞事件循環(huán)的耗時(shí)長(zhǎng)的繁重計(jì)算任務(wù),我們可以使用 Web Workers[4]。

    這是在另一個(gè)并行線程中運(yùn)行代碼的方式。

    Web Workers 可以與主線程交換消息,但是它們具有自己的變量和事件循環(huán)。

    Web Workers 沒有訪問 DOM 的權(quán)限,因此,它們對(duì)于同時(shí)使用多個(gè) CPU 內(nèi)核的計(jì)算非常有用。

    參考資料

    [1]創(chuàng)建自定義事件: https://zh.javascript.info/dispatch-events

    [2]微任務(wù)隊(duì)列: https://zh.javascript.info/microtask-queue

    [3]規(guī)范: https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model

    [4]Web Workers: https://html.spec.whatwg.org/multipage/workers.html

    [5]React 官方文檔推薦,與 MDN 并列的 JavaScript 學(xué)習(xí)教程: https://zh-hans.reactjs.org/docs/getting-started.html#javascript-resources

    本文轉(zhuǎn)載自微信公眾號(hào)「技術(shù)漫談」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系技術(shù)漫談公眾號(hào)。


    文章標(biāo)題:圖解JavaScript事件循環(huán):微任務(wù)和宏任務(wù)
    本文網(wǎng)址:http://www.5511xx.com/article/codicpd.html