欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文帶你掌握J(rèn)avaScript中的EventLoop機(jī)制

 更新時(shí)間:2024年02月20日 11:48:16   作者:柏油  
JavaScript是?單線程、非阻塞?的,它通過事件隊(duì)列?(Event?Loop)?的方式來實(shí)現(xiàn)異步回調(diào),所以本文小編就帶大家來深入了解一下JavaScript中的EventLoop機(jī)制,需要的可以了解下

EventLoop

JavaScript是 單線程、非阻塞 的,它通過事件隊(duì)列 (Event Loop) 的方式來實(shí)現(xiàn)異步回調(diào)。

關(guān)鍵點(diǎn)

  • 單線程:JavaScript是單線程的,即同一個(gè)時(shí)間只能做一件事,事件循環(huán)使其能夠高效地處理異步操作。
  • 非阻塞式I/O:事件循環(huán)使得JavaScript可以執(zhí)行長(zhǎng)時(shí)間運(yùn)行的任務(wù)(如I/O操作),而不會(huì)阻塞線程。
  • 微任務(wù)優(yōu)先:在每個(gè)宏任務(wù)(Macrotask)執(zhí)行完畢后,立即執(zhí)行當(dāng)前 微任務(wù)隊(duì)列 中的所有微任務(wù)(依次執(zhí)行),在進(jìn)行下一個(gè)宏任務(wù)之前。

為什么 javascript 是單線程的

我們知道多線程可以提高效率啊,為什么JavaScript被設(shè)計(jì)為單線程,主要原因是它創(chuàng)建的初衷:與用戶的交互以及操作DOM。

在Web頁面中,腳本需要響應(yīng)用戶的操作:如點(diǎn)擊按鈕、提交表單等,這些操作涉及到對(duì)DOM的讀寫。假如JavaScript是多線程的,那么就會(huì)引入復(fù)雜的同步問題。

例如:兩個(gè)線程同時(shí)嘗試修改同一個(gè)DOM節(jié)點(diǎn),那么會(huì)產(chǎn)生競(jìng)態(tài)條件,導(dǎo)致不可預(yù)測(cè)的結(jié)果。所以js一誕生就是單線程并且未來也不會(huì)改變

為了利用多核CPU的計(jì)算能力,HTML5提出Web Worker標(biāo)準(zhǔn),允許JavaScript腳本創(chuàng)建多個(gè)線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個(gè)新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)。

簡(jiǎn)化開發(fā)

單線程模型簡(jiǎn)化了JavaScript的設(shè)計(jì)和使用。開發(fā)者可以更專注于實(shí)現(xiàn)功能,而不用擔(dān)心如線程同步、死鎖等多線程編程中常見的問題。

避免DOM操作沖突

javascript選擇只用一個(gè)主線程來執(zhí)行代碼,任何時(shí)刻只有一個(gè)操作可以被執(zhí)行,從而保證了DOM操作的一致性和可預(yù)測(cè)性。

事件循環(huán)和異步編程

盡管JavaScript是單線程的,但它通過事件循環(huán)(Event Loop)機(jī)制支持異步編程。事件循環(huán)允許JavaScript在執(zhí)行I/O密集型或耗時(shí)任務(wù)(如Ajax請(qǐng)求、文件操作等)時(shí),不會(huì)阻塞主線程。

這是通過將這些任務(wù)設(shè)置為異步操作并配合回調(diào)函數(shù)、Promise或async/await來實(shí)現(xiàn)的。事件循環(huán)和異步編程模型使JavaScript能夠高效地處理多種操作,而無需引入多線程的復(fù)雜性。

什么是非阻塞

JavaScript的非阻塞特性是指在執(zhí)行耗時(shí)操作(如I/O操作、請(qǐng)求數(shù)據(jù)等)時(shí),不會(huì)阻塞程序的其他部分繼續(xù)執(zhí)行。

這種特性是通過異步編程模式實(shí)現(xiàn)的,它允許JavaScript在等待某個(gè)操作完成的同時(shí),繼續(xù)執(zhí)行代碼的其他部分,從而提高程序的整體性能和響應(yīng)能力。

為什么需要非阻塞

在瀏覽器環(huán)境中,JavaScript運(yùn)行在單線程中,這意味著在同一時(shí)間內(nèi)只能執(zhí)行一個(gè)任務(wù)。如果JavaScript執(zhí)行一個(gè)長(zhǎng)時(shí)間運(yùn)行的任務(wù),如從服務(wù)器下載大量數(shù)據(jù),它將阻塞后續(xù)代碼的執(zhí)行,導(dǎo)致整個(gè)頁面無法響應(yīng)用戶操作,甚至出現(xiàn)卡頓。

通過非阻塞異步編程,JavaScript可以在等待某個(gè)長(zhǎng)時(shí)間運(yùn)行的任務(wù)完成的同時(shí),繼續(xù)執(zhí)行其他任務(wù),提高應(yīng)用的響應(yīng)性和用戶體驗(yàn)。

實(shí)現(xiàn)非阻塞的方式有哪些?

1) 回調(diào)函數(shù)(Callbacks)

最初,JavaScript通過回調(diào)函數(shù)實(shí)現(xiàn)非阻塞行為。當(dāng)一個(gè)異步操作開始時(shí),會(huì)傳入一個(gè)函數(shù)(回調(diào)函數(shù)),這個(gè)函數(shù)會(huì)在異步操作完成時(shí)被調(diào)用。

這種方式雖然解決了非阻塞的問題,但當(dāng)有多個(gè)異步操作需要協(xié)同工作時(shí),會(huì)導(dǎo)致所謂的“回調(diào)地獄”(Callback Hell),使得代碼難以閱讀和維護(hù)。

2) Promise

為了解決回調(diào)函數(shù)帶來的問題,ES6引入了Promise對(duì)象。Promise提供了一種更優(yōu)雅的方式來處理異步操作。

它代表了一個(gè)異步操作的最終完成(或失敗)及其結(jié)果值。通過.then()和.catch()方法,可以更容易地組織和管理異步操作及其結(jié)果。

3)async/await

ES7進(jìn)一步引入了asyncawait關(guān)鍵字,使得使用Promise的代碼可以像寫同步代碼那樣簡(jiǎn)潔明了。

async函數(shù)聲明一個(gè)函數(shù)是異步的,而await關(guān)鍵字用于等待一個(gè)Promise解決(resolve)。使用asyncawait可以以同步的方式寫出清晰、易讀的代碼,同時(shí)保持異步操作的非阻塞特性。

同步任務(wù)、異步任務(wù)、宏任務(wù)、微任務(wù)之間的概念和關(guān)系

JS 分為同步任務(wù)和異步任務(wù);同步任務(wù)都在JS引擎線程上執(zhí)行,形成一個(gè)執(zhí)行棧,它們與事件循環(huán)無關(guān);異步任務(wù)被分為宏任務(wù)和微任務(wù),它們都依賴事件循環(huán)進(jìn)行調(diào)度,但執(zhí)行時(shí)機(jī)不同;

事件觸發(fā)線程管理一個(gè)任務(wù)隊(duì)列,異步任務(wù)觸發(fā)條件達(dá)成,將回調(diào)事件放到任務(wù)隊(duì)列中。

同步任務(wù):這些任務(wù)在主線程上按順序執(zhí)行,執(zhí)行過程會(huì)阻塞后續(xù)任務(wù)的執(zhí)行,直到當(dāng)前任務(wù)完成。同步任務(wù)的執(zhí)行不依賴事件循環(huán),它們直接在調(diào)用棧(執(zhí)行棧)中按順序執(zhí)行。

異步任務(wù):異步任務(wù)的執(zhí)行不會(huì)立即完成,它們依賴事件循環(huán)進(jìn)行調(diào)度。異步任務(wù)包括宏任務(wù)和微任務(wù),它們?cè)谔囟ǖ臅r(shí)間點(diǎn)被推入各自的隊(duì)列中等待執(zhí)行。

宏任務(wù)(Macrotasks)

宏任務(wù)是一類異步任務(wù),它們代表了一些較大的、獨(dú)立的工作單元。每個(gè)宏任務(wù)的執(zhí)行會(huì)在一個(gè)新的事件循環(huán)中進(jìn)行,包括:setTimeout、setInterval、I/O 操作、UI 渲染(在瀏覽器環(huán)境中)、postMessage

微任務(wù)(Microtasks)

微任務(wù)也是異步任務(wù),但它們用于處理一些需要盡快執(zhí)行的較小的工作單元。**微任務(wù)在當(dāng)前宏任務(wù)執(zhí)行完畢后、下一個(gè)宏任務(wù)開始之前執(zhí)行。包括:Promise(??promise本身是同步的,回調(diào)函數(shù)才是異步的)的回調(diào)(.then、.catch、.finally)、MutationObserver的回調(diào)、queueMicrotask

一次事件循環(huán)的執(zhí)行

  • 執(zhí)行當(dāng)前宏任務(wù):事件循環(huán)首先從宏任務(wù)隊(duì)列(也稱為任務(wù)隊(duì)列)中取出第一個(gè)任務(wù)執(zhí)行。這包括了諸如setTimeoutsetInterval、I/O 操作、用戶交互事件(如點(diǎn)擊或鍵盤事件)等任務(wù)。
  • 執(zhí)行所有微任務(wù):當(dāng)前宏任務(wù)執(zhí)行完畢后,事件循環(huán)會(huì)檢查微任務(wù)隊(duì)列。如果隊(duì)列中有微任務(wù)(例如,由Promise.then()MutationObserver等產(chǎn)生的任務(wù)),事件循環(huán)會(huì)依次執(zhí)行隊(duì)列中的所有微任務(wù),直到微任務(wù)隊(duì)列清空。微任務(wù)的執(zhí)行是連續(xù)的,不會(huì)中斷。
  • 渲染UI(如果需要):在瀏覽器環(huán)境中,一旦微任務(wù)隊(duì)列清空,瀏覽器會(huì)檢查是否需要執(zhí)行UI渲染。通常,瀏覽器的UI渲染會(huì)在執(zhí)行完所有微任務(wù)之后,下一個(gè)宏任務(wù)開始之前進(jìn)行。
  • 繼續(xù)下一個(gè)宏任務(wù):完成當(dāng)前宏任務(wù)、所有微任務(wù)以及可能的UI渲染之后,事件循環(huán)會(huì)回到第一步,從宏任務(wù)隊(duì)列中取出下一個(gè)任務(wù),開始新一輪的執(zhí)行。

在同一次事件循環(huán)中,微任務(wù)(Microtasks)總是在當(dāng)前宏任務(wù)(Macrotasks)之后執(zhí)行。

上圖中,主線程運(yùn)行的時(shí)候,產(chǎn)生堆(heap)和棧(stack),棧中的代碼調(diào)用各種外部API,它們?cè)?quot;任務(wù)隊(duì)列"中加入各種事件(click,load,done)。

只要棧中的代碼執(zhí)行完畢,主線程就會(huì)去讀取"任務(wù)隊(duì)列",依次執(zhí)行那些事件所對(duì)應(yīng)的回調(diào)函數(shù)。

實(shí)踐

setTimeout(() => { 
  console.log(1)
}, 0) 
console.log(2)
const promise2 = new Promise((resolve) => {
  console.log(3)
  resolve(3) 
}) 
promise2.then((res) => { 
  console.log(4) 
})

執(zhí)行步驟和輸出結(jié)果的解釋:

  • setTimeout(() => { console.log(1) }, 0)  注冊(cè)了一個(gè)宏任務(wù),但它的回調(diào)函數(shù)(打印1)不會(huì)立即執(zhí)行。放入宏任務(wù)隊(duì)列中,等待當(dāng)前執(zhí)行棧清空和所有微任務(wù)完成后再執(zhí)行。
  • console.log(2) 是同步代碼,會(huì)立即執(zhí)行,輸出2。
  • 創(chuàng)建了一個(gè)新的Promise對(duì)象promise2,*console.log(3)*也是同步代碼,因此會(huì)立即執(zhí)行,輸出3。
  • 在Promise的executor函數(shù)中,調(diào)用resolve(3)。這會(huì)將 promise2.then((res) => { console.log(4) }) 中的回調(diào)函數(shù)加入到微任務(wù)隊(duì)列,等待當(dāng)前執(zhí)行棧清空后執(zhí)行。
  • 此時(shí),同步代碼執(zhí)行完畢。
  • 在進(jìn)入下一個(gè)宏任務(wù)之前,事件循環(huán)會(huì)處理所有微任務(wù)。因此,promise2.then()的回調(diào)函數(shù)會(huì)被執(zhí)行,輸出4
  • 最后,事件循環(huán)處理下一個(gè)宏任務(wù),即 setTimeout() 的回調(diào)函數(shù),執(zhí)行并輸出1。

所以,輸出結(jié)果為:23、4、1。

js整體執(zhí)行順序是:同步任務(wù) -> 微任務(wù) -> 宏任務(wù) -> 微任務(wù) -> 宏任務(wù) -> ...

總結(jié)

  • 執(zhí)行一個(gè)宏任務(wù)(棧中沒有就從事件隊(duì)列中獲?。?/li>
  • 執(zhí)行過程中如果遇到微任務(wù),就將它添加到微任務(wù)的任務(wù)隊(duì)列中
  • 宏任務(wù)執(zhí)行完畢后,立即執(zhí)行當(dāng)前微任務(wù)隊(duì)列中的所有微任務(wù)(依次執(zhí)行)
  • 當(dāng)前宏任務(wù)執(zhí)行完畢,開始檢查渲染,然后GUI線程接管渲染
  • 渲染完畢后,JS線程繼續(xù)接管,開始下一個(gè)宏任務(wù)(從事件隊(duì)列中獲?。?/li>

分享一個(gè)實(shí)用工具:Event Loop可視化面板

到此這篇關(guān)于一文帶你掌握J(rèn)avaScript中的EventLoop機(jī)制的文章就介紹到這了,更多相關(guān)JavaScript EventLoop機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 帶你領(lǐng)略O(shè)bject.assign()方法的操作方式

    帶你領(lǐng)略O(shè)bject.assign()方法的操作方式

    這篇文章主要介紹了帶你領(lǐng)略O(shè)bject.assign()方法的操作方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 一文帶你搞懂JavaScript中轉(zhuǎn)義字符的使用

    一文帶你搞懂JavaScript中轉(zhuǎn)義字符的使用

    說起轉(zhuǎn)義字符,大家最先想到的肯定是使用反斜杠,這也是我們最常見的,很多編程語言都支持。除了反斜杠以外,在前端開發(fā)中,還有其他幾種轉(zhuǎn)義字符,也是較常見的,本文將對(duì)這些做一個(gè)總結(jié)
    2023-02-02
  • JavaScript函數(shù)中this指向問題詳解

    JavaScript函數(shù)中this指向問題詳解

    這篇文章主要給大家介紹了關(guān)于JavaScript函數(shù)中this指向問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • JavaScript搜索字符串并將搜索結(jié)果返回到字符串的方法

    JavaScript搜索字符串并將搜索結(jié)果返回到字符串的方法

    這篇文章主要介紹了JavaScript搜索字符串并將搜索結(jié)果返回到字符串的方法,涉及javascript中match方法操作字符串的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • setTimeout自動(dòng)觸發(fā)一個(gè)js的方法

    setTimeout自動(dòng)觸發(fā)一個(gè)js的方法

    本文為大家介紹下使用setTimeout自動(dòng)觸發(fā)一個(gè)js,具體實(shí)現(xiàn)如下,喜歡的朋友可以學(xué)習(xí)下
    2014-01-01
  • 詳解JS對(duì)象封裝的常用方式

    詳解JS對(duì)象封裝的常用方式

    JS是一門面向?qū)ο笳Z言,其對(duì)象是用prototype屬性來模擬的,本文介紹了如何封裝JS對(duì)象,具有一定的參考價(jià)值,下面跟著小編一起來看下吧
    2016-12-12
  • (推薦一個(gè)超好的JS函數(shù)庫)S.Sams Lifexperience ScriptClassLib

    (推薦一個(gè)超好的JS函數(shù)庫)S.Sams Lifexperience ScriptClassLib

    (推薦一個(gè)超好的JS函數(shù)庫)S.Sams Lifexperience ScriptClassLib...
    2007-04-04
  • js代碼運(yùn)行報(bào)錯(cuò)Warning:To?load?an?ES?module,?set?"type":"module"in?the?package.json?or?use?the?.mjs

    js代碼運(yùn)行報(bào)錯(cuò)Warning:To?load?an?ES?module,?set?"type&q

    最近在學(xué)習(xí)ES6的過程中,和運(yùn)行javascript文件時(shí)進(jìn)行了報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于js代碼運(yùn)行報(bào)錯(cuò)Warning:To?load?an?ES?module,?set?"type":"module"in?the?package.json?or?use?the?.mjs的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • 根據(jù)分辯率調(diào)用不同的CSS.

    根據(jù)分辯率調(diào)用不同的CSS.

    根據(jù)分辯率調(diào)用不同的CSS....
    2007-01-01
  • 淺談JavaScript之事件綁定

    淺談JavaScript之事件綁定

    關(guān)于 JavaScript 的事件綁定在網(wǎng)上已經(jīng)有不少相關(guān)的資料了,今天這篇文章也是在被同事問及的時(shí)候才順便把它記錄下來,算是 JavaScript 事件綁定中的一個(gè)小技巧,如果能在工作中善加利用,會(huì)有出其不意的效果
    2013-07-07

最新評(píng)論