最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

事件循環(huán)

2023-08-08 02:57 作者:十三他很帥  | 我要投稿

事件循環(huán)及其相關(guān)概念:調(diào)用堆棧、任務(wù)隊列與微任務(wù)隊列

事件循環(huán)是 JavaScript 引擎中一個至關(guān)重要的部分,它使得 JavaScript 能夠在單線程中以非阻塞的方式執(zhí)行。要理解事件循環(huán)是如何工作的,我們需要首先了解一些關(guān)鍵概念,包括調(diào)用堆棧、任務(wù)、微任務(wù)及它們各自所在的隊列。

調(diào)用堆棧(Call Stack)

調(diào)用堆棧是一種數(shù)據(jù)結(jié)構(gòu),用于跟蹤正在執(zhí)行的 JavaScript 代碼中的函數(shù)調(diào)用。顧名思義,調(diào)用堆棧是一個堆棧,即內(nèi)存中的后進(jìn)先出(LIFO)數(shù)據(jù)結(jié)構(gòu)。每個被執(zhí)行的函數(shù)都表示為調(diào)用堆棧中的一個幀,會在前一個函數(shù)之上入棧。

讓我們通過一個簡單的例子來逐步了解這個過程:

  1. 調(diào)用堆棧最初為空。

  2. 函數(shù) foo() 被壓入調(diào)用堆棧。

  3. 函數(shù) foo() 被執(zhí)行并從調(diào)用堆棧中彈出。

  4. 函數(shù) console.log('foo') 被推送到調(diào)用堆棧上。

  5. 函數(shù) console.log('foo') 被執(zhí)行并從調(diào)用堆棧中彈出。

  6. 函數(shù) bar() 被壓入調(diào)用堆棧。

  7. 函數(shù) bar() 被執(zhí)行并從調(diào)用堆棧中彈出。

  8. 函數(shù) console.log('bar') 被推送到調(diào)用堆棧上。

  9. 函數(shù) console.log('bar') 被執(zhí)行并從調(diào)用堆棧中彈出。

  10. 調(diào)用堆?,F(xiàn)在為空。

任務(wù)(Task)與任務(wù)隊列(Task Queue)

任務(wù)是預(yù)定的、同步執(zhí)行的代碼塊。在執(zhí)行過程中,它們對調(diào)用堆棧具有獨占訪問權(quán)限,并且可以將其他任務(wù)排入隊列。任務(wù)之間可執(zhí)行渲染更新。任務(wù)存儲在任務(wù)隊列中,并等待著相關(guān)函數(shù)執(zhí)行。任務(wù)隊列是一個先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu)。典型的任務(wù)示例包括事件監(jiān)聽器回調(diào)函數(shù)以及 setTimeout() 的回調(diào)。

微任務(wù)(Microtask)與微任務(wù)隊列(Microtask Queue)

微任務(wù)與任務(wù)類似,因為它們也是預(yù)定的同步執(zhí)行的代碼塊,并在執(zhí)行過程中對調(diào)用堆棧具有獨占訪問權(quán)限。此外,它們還存儲在自己的先進(jìn)先出(FIFO)數(shù)據(jù)結(jié)構(gòu)中,即微任務(wù)隊列。然而,微任務(wù)與任務(wù)的區(qū)別在于,它們會在當(dāng)前任務(wù)執(zhí)行完畢之后以及重新渲染之前立即執(zhí)行。典型的微任務(wù)示例包括 Promise 回調(diào)和 MutationObserver 回調(diào)。

事件循環(huán)(Event Loop)

事件循環(huán)是一個持續(xù)運行并檢查調(diào)用堆棧是否為空的過程。它通過將任務(wù)和微任務(wù)逐個放入調(diào)用堆棧中來處理它們,并對渲染過程進(jìn)行控制。事件循環(huán)的核心包含四個關(guān)鍵步驟:

  1. 腳本評估:逐個執(zhí)行腳本內(nèi)的代碼,直到調(diào)用堆棧為空。

  2. 任務(wù)處理:選擇任務(wù)隊列中的第一個任務(wù),然后執(zhí)行它,一直執(zhí)行到調(diào)用堆棧為空。

  3. 微任務(wù)處理:從微任務(wù)隊列中取出第一個微任務(wù)執(zhí)行,直至調(diào)用堆棧為空,重復(fù)此過程直至微任務(wù)隊列為空。

  4. 渲染:重新渲染 UI 界面,并循環(huán)回到步驟 2。

實際示例

為了更好地理解事件循環(huán)機(jī)制,我們可以看一個涵蓋了上述所有概念的實際示例:

讓我們逐步分析這個過程:

  1. 調(diào)用堆棧最初為空。事件循環(huán)開始評估腳本。

  2. console.log() 入棧并執(zhí)行,輸出 "Script start"。

  3. setTimeout() 入棧并執(zhí)行。該操作會在任務(wù)隊列中為其回調(diào)函數(shù)創(chuàng)建一個新任務(wù)。

  4. Promise.prototype.resolve() 入棧并執(zhí)行,然后依次調(diào)用 Promise.prototype.then()。

  5. Promise.prototype.then() 入棧并執(zhí)行。這會在微任務(wù)隊列中為其回調(diào)函數(shù)創(chuàng)建一個新的微任務(wù)。

  6. console.log() 入棧并執(zhí)行,輸出 "Script end"。

  7. 事件循環(huán)已完成其當(dāng)前任務(wù)(評估腳本),接著開始處理微任務(wù)隊列中的第一個微任務(wù),即在步驟 5 中排入隊列的 Promise.prototype.then() 的回調(diào)。

  8. console.log() 入棧并執(zhí)行,輸出 "Promise.then() #1"。

  9. Promise.prototype.then() 入棧并執(zhí)行。這會在微任務(wù)隊列中為其回調(diào)函數(shù)創(chuàng)建一個新條目。

  10. 事件循環(huán)檢查微任務(wù)隊列。因為它還不為空,所以會繼續(xù)執(zhí)行隊列中的第一個微任務(wù)——在步驟 10 中排入隊列的 Promise.prototype.then() 的回調(diào)。

  11. console.log() 入棧并執(zhí)行,輸出 "Promise.then() #2"。

  12. 如果有的話,在此處進(jìn)行重新渲染。

  13. 由于微任務(wù)隊列已經(jīng)為空,事件循環(huán)將轉(zhuǎn)到任務(wù)隊列,并執(zhí)行第一個任務(wù)。這是在步驟 3 中排入隊列的 setTimeout() 的回調(diào)。

  14. console.log() 入棧并執(zhí)行,輸出 "setTimeout()"。

  15. 如果有的話,在此處進(jìn)行重新渲染。

  16. 調(diào)用堆?,F(xiàn)在為空。

總結(jié)

  • 事件循環(huán)負(fù)責(zé)執(zhí)行 JavaScript 代碼。首先處理腳本評估和執(zhí)行,然后處理任務(wù)和微任務(wù)。

  • 任務(wù)和微任務(wù)都是預(yù)定的同步代碼塊。它們逐個執(zhí)行,并分別放置在任務(wù)隊列和微任務(wù)隊列中。

  • 調(diào)用堆棧跟蹤 JavaScript 中的函數(shù)調(diào)用。

  • 每次執(zhí)行微任務(wù)時,都需要清空微任務(wù)隊列,然后才能進(jìn)行下一個任務(wù)的處理。

  • 渲染工作發(fā)生在任務(wù)之間,但不會發(fā)生在微任務(wù)之間。

附加說明

  • 事件循環(huán)的腳本評估步驟本身與任務(wù)類似,即按順序執(zhí)行直至結(jié)束。

  • setTimeout() 的第二個參數(shù)表示執(zhí)行前的最短延遲時間,而非保證時間。這是因為任務(wù)會按順序執(zhí)行,而微任務(wù)可能在此期間插入執(zhí)行。

  • 在 Node.js 中,事件循環(huán)的行為類似于在瀏覽器中的行為。但它們之間也存在一些差異,最明顯的區(qū)別是不存在渲染步驟。

  • 較舊版本的瀏覽器可能不會完全遵循這種操作順序,因此任務(wù)和微任務(wù)可能會以不同的順序執(zhí)行。



事件循環(huán)的評論 (共 條)

分享到微博請遵守國家法律
保定市| 海门市| 呼和浩特市| 临洮县| 安化县| 理塘县| 青浦区| 许昌市| 城步| 山西省| 武隆县| 和田市| 鞍山市| 雷波县| 吐鲁番市| 常德市| 从江县| 晋江市| 高青县| 葫芦岛市| 安岳县| 宁明县| 崇明县| 榆树市| 太仓市| 昌黎县| 突泉县| 馆陶县| 河曲县| 清原| 神农架林区| 广安市| 莱芜市| 安宁市| 遵义市| 徐汇区| 古交市| 同仁县| 龙州县| 涿鹿县| 甘洛县|