成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JS瀏覽器事件循環(huán)機(jī)制

zebrayoung / 3500人閱讀

摘要:事件循環(huán)機(jī)制事件循環(huán)機(jī)制分為瀏覽器和事件循環(huán)機(jī)制,兩者的實(shí)現(xiàn)技術(shù)不一樣,瀏覽器是中定義的規(guī)范,是由庫(kù)實(shí)現(xiàn)。整個(gè)事件循環(huán)完成之后,會(huì)去檢測(cè)微任務(wù)的任務(wù)隊(duì)列中是否存在任務(wù),存在就執(zhí)行。

文章來(lái)自我的 github 博客,包括技術(shù)輸出和學(xué)習(xí)筆記,歡迎star。

先來(lái)明白些概念性內(nèi)容。

進(jìn)程、線程

進(jìn)程是系統(tǒng)分配的獨(dú)立資源,是 CPU 資源分配的基本單位,進(jìn)程是由一個(gè)或者多個(gè)線程組成的。

線程是進(jìn)程的執(zhí)行流,是CPU調(diào)度和分派的基本單位,同個(gè)進(jìn)程之中的多個(gè)線程之間是共享該進(jìn)程的資源的。

瀏覽器內(nèi)核

瀏覽器是多進(jìn)程的,瀏覽器每一個(gè) tab 標(biāo)簽都代表一個(gè)獨(dú)立的進(jìn)程(也不一定,因?yàn)槎鄠€(gè)空白 tab 標(biāo)簽會(huì)合并成一個(gè)進(jìn)程),瀏覽器內(nèi)核(瀏覽器渲染進(jìn)程)屬于瀏覽器多進(jìn)程中的一種。

瀏覽器內(nèi)核有多種線程在工作。

GUI 渲染線程:

負(fù)責(zé)渲染頁(yè)面,解析 HTML,CSS 構(gòu)成 DOM 樹(shù)等,當(dāng)頁(yè)面重繪或者由于某種操作引起回流都會(huì)調(diào)起該線程。

和 JS 引擎線程是互斥的,當(dāng) JS 引擎線程在工作的時(shí)候,GUI 渲染線程會(huì)被掛起,GUI 更新被放入在 JS 任務(wù)隊(duì)列中,等待 JS 引擎線程空閑的時(shí)候繼續(xù)執(zhí)行。

JS 引擎線程:

單線程工作,負(fù)責(zé)解析運(yùn)行 JavaScript 腳本。

和 GUI 渲染線程互斥,JS 運(yùn)行耗時(shí)過(guò)長(zhǎng)就會(huì)導(dǎo)致頁(yè)面阻塞。

事件觸發(fā)線程:

當(dāng)事件符合觸發(fā)條件被觸發(fā)時(shí),該線程會(huì)把對(duì)應(yīng)的事件回調(diào)函數(shù)添加到任務(wù)隊(duì)列的隊(duì)尾,等待 JS 引擎處理。

定時(shí)器觸發(fā)線程:

瀏覽器定時(shí)計(jì)數(shù)器并不是由 JS 引擎計(jì)數(shù)的,阻塞會(huì)導(dǎo)致計(jì)時(shí)不準(zhǔn)確。

開(kāi)啟定時(shí)器觸發(fā)線程來(lái)計(jì)時(shí)并觸發(fā)計(jì)時(shí),計(jì)時(shí)完成后會(huì)被添加到任務(wù)隊(duì)列中,等待 JS 引擎處理。

http 請(qǐng)求線程:

http 請(qǐng)求的時(shí)候會(huì)開(kāi)啟一條請(qǐng)求線程。

請(qǐng)求完成有結(jié)果了之后,將請(qǐng)求的回調(diào)函數(shù)添加到任務(wù)隊(duì)列中,等待 JS 引擎處理。

JavaScript 引擎是單線程

JavaScript 引擎是單線程,也就是說(shuō)每次只能執(zhí)行一項(xiàng)任務(wù),其他任務(wù)都得按照順序排隊(duì)等待被執(zhí)行,只有當(dāng)前的任務(wù)執(zhí)行完成之后才會(huì)往下執(zhí)行下一個(gè)任務(wù)。

HTML5 中提出了 Web-Worker API,主要是為了解決頁(yè)面阻塞問(wèn)題,但是并沒(méi)有改變 JavaScript 是單線程的本質(zhì)。了解 Web-Worker。

JavaScript 事件循環(huán)機(jī)制

JavaScript 事件循環(huán)機(jī)制分為瀏覽器和 Node 事件循環(huán)機(jī)制,兩者的實(shí)現(xiàn)技術(shù)不一樣,瀏覽器 Event Loop 是 HTML 中定義的規(guī)范,Node Event Loop 是由 libuv 庫(kù)實(shí)現(xiàn)。這里主要講的是瀏覽器部分。

Javascript 有一個(gè) main thread 主線程和 call-stack 調(diào)用棧(執(zhí)行棧),所有的任務(wù)都會(huì)被放到調(diào)用棧等待主線程執(zhí)行。

JS 調(diào)用棧

JS 調(diào)用棧是一種后進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)。當(dāng)函數(shù)被調(diào)用時(shí),會(huì)被添加到棧中的頂部,執(zhí)行完成之后就從棧頂部移出該函數(shù),直到棧內(nèi)被清空。

同步任務(wù)、異步任務(wù)

JavaScript 單線程中的任務(wù)分為同步任務(wù)和異步任務(wù)。同步任務(wù)會(huì)在調(diào)用棧中按照順序排隊(duì)等待主線程執(zhí)行,異步任務(wù)則會(huì)在異步有了結(jié)果后將注冊(cè)的回調(diào)函數(shù)添加到任務(wù)隊(duì)列(消息隊(duì)列)中等待主線程空閑的時(shí)候,也就是棧內(nèi)被清空的時(shí)候,被讀取到棧中等待主線程執(zhí)行。任務(wù)隊(duì)列是先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)。

Event Loop

調(diào)用棧中的同步任務(wù)都執(zhí)行完畢,棧內(nèi)被清空了,就代表主線程空閑了,這個(gè)時(shí)候就會(huì)去任務(wù)隊(duì)列中按照順序讀取一個(gè)任務(wù)放入到棧中執(zhí)行。每次棧內(nèi)被清空,都會(huì)去讀取任務(wù)隊(duì)列有沒(méi)有任務(wù),有就讀取執(zhí)行,一直循環(huán)讀取-執(zhí)行的操作,就形成了事件循環(huán)。

定時(shí)器

定時(shí)器會(huì)開(kāi)啟一條定時(shí)器觸發(fā)線程來(lái)觸發(fā)計(jì)時(shí),定時(shí)器會(huì)在等待了指定的時(shí)間后將事件放入到任務(wù)隊(duì)列中等待讀取到主線程執(zhí)行。

定時(shí)器指定的延時(shí)毫秒數(shù)其實(shí)并不準(zhǔn)確,因?yàn)槎〞r(shí)器只是在到了指定的時(shí)間時(shí)將事件放入到任務(wù)隊(duì)列中,必須要等到同步的任務(wù)和現(xiàn)有的任務(wù)隊(duì)列中的事件全部執(zhí)行完成之后,才會(huì)去讀取定時(shí)器的事件到主線程執(zhí)行,中間可能會(huì)存在耗時(shí)比較久的任務(wù),那么就不可能保證在指定的時(shí)間執(zhí)行。

宏任務(wù)(macro-task)、微任務(wù)(micro-task)

除了廣義的同步任務(wù)和異步任務(wù),JavaScript 單線程中的任務(wù)可以細(xì)分為宏任務(wù)和微任務(wù)。

macro-task包括:script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering。

micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver。

    console.log(1);
    setTimeout(function() {
        console.log(2);
    })
    var promise = new Promise(function(resolve, reject) {
        console.log(3);
        resolve();
    })
    promise.then(function() {
        console.log(4);
    })
    console.log(5);

示例中,setTimeout 和 Promise被稱為任務(wù)源,來(lái)自不同的任務(wù)源注冊(cè)的回調(diào)函數(shù)會(huì)被放入到不同的任務(wù)隊(duì)列中。

有了宏任務(wù)和微任務(wù)的概念后,那 JS 的執(zhí)行順序是怎樣的?是宏任務(wù)先還是微任務(wù)先?

第一次事件循環(huán)中,JavaScript 引擎會(huì)把整個(gè) script 代碼當(dāng)成一個(gè)宏任務(wù)執(zhí)行,執(zhí)行完成之后,再檢測(cè)本次循環(huán)中是否尋在微任務(wù),存在的話就依次從微任務(wù)的任務(wù)隊(duì)列中讀取執(zhí)行完所有的微任務(wù),再讀取宏任務(wù)的任務(wù)隊(duì)列中的任務(wù)執(zhí)行,再執(zhí)行所有的微任務(wù),如此循環(huán)。JS 的執(zhí)行順序就是每次事件循環(huán)中的宏任務(wù)-微任務(wù)。

上面的示例中,第一次事件循環(huán),整段代碼作為宏任務(wù)進(jìn)入主線程執(zhí)行。

遇到了 setTimeout ,就會(huì)等到過(guò)了指定的時(shí)間后將回調(diào)函數(shù)放入到宏任務(wù)的任務(wù)隊(duì)列中。

遇到 Promise,將 then 函數(shù)放入到微任務(wù)的任務(wù)隊(duì)列中。

整個(gè)事件循環(huán)完成之后,會(huì)去檢測(cè)微任務(wù)的任務(wù)隊(duì)列中是否存在任務(wù),存在就執(zhí)行。

第一次的循環(huán)結(jié)果打印為: 1,3,5,4。

接著再到宏任務(wù)的任務(wù)隊(duì)列中按順序取出一個(gè)宏任務(wù)到棧中讓主線程執(zhí)行,那么在這次循環(huán)中的宏任務(wù)就是 setTimeout 注冊(cè)的回調(diào)函數(shù),執(zhí)行完這個(gè)回調(diào)函數(shù),發(fā)現(xiàn)在這次循環(huán)中并不存在微任務(wù),就準(zhǔn)備進(jìn)行下一次事件循環(huán)。

檢測(cè)到宏任務(wù)隊(duì)列中已經(jīng)沒(méi)有了要執(zhí)行的任務(wù),那么就結(jié)束事件循環(huán)。

最終的結(jié)果就是 1,3,5,4,2。

參考

https://juejin.im/post/59e85eebf265da430d571f89

https://juejin.im/post/59c25c936fb9a00a3f24e114

https://segmentfault.com/a/1190000012925872

https://zhuanlan.zhihu.com/p/26229293

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

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

相關(guān)文章

  • JavaScript運(yùn)行機(jī)制事件循環(huán)

    摘要:主線程不斷重復(fù)上面的三步,此過(guò)程也就是常說(shuō)的事件循環(huán)。所以主線程代碼執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)阻塞事件循環(huán)的執(zhí)行。參考資料這一次,徹底弄懂執(zhí)行機(jī)制任務(wù)隊(duì)列的順序機(jī)制事件循環(huán)搞懂異步事件輪詢與中的事件循環(huán) 1. 說(shuō)明 讀過(guò)本文章后,您能知道: JavaScript代碼在瀏覽器中的執(zhí)行機(jī)制和事件循環(huán) 面試中經(jīng)常遇到的代碼輸出順序問(wèn)題 首先通過(guò)一段代碼來(lái)驗(yàn)證你是否了解代碼輸出順序,如果你不知道輸出...

    Ververica 評(píng)論0 收藏0
  • Js事件循環(huán)(Event Loop)機(jī)制以及實(shí)例講解

    摘要:主線程要明確的一點(diǎn)是,主線程跟執(zhí)行棧是不同概念,主線程規(guī)定現(xiàn)在執(zhí)行執(zhí)行棧中的哪個(gè)事件。主線程循環(huán)即主線程會(huì)不停的從執(zhí)行棧中讀取事件,會(huì)執(zhí)行完所有棧中的同步代碼。以上參考資料詳解中的事件循環(huán)機(jī)制中的事件循環(huán)運(yùn)行機(jī)制詳解再談 showImg(https://segmentfault.com/img/remote/1460000015317437?w=1920&h=1080); 前言 大家都...

    Anshiii 評(píng)論0 收藏0
  • 淺談不同環(huán)境下的JavaScript執(zhí)行機(jī)制 + 示例詳解

    摘要:如果沒(méi)有其他異步任務(wù)要處理比如到期的定時(shí)器,會(huì)一直停留在這個(gè)階段,等待請(qǐng)求返回結(jié)果。執(zhí)行的執(zhí)行事件關(guān)閉請(qǐng)求的,例如事件循環(huán)的每一次循環(huán)都需要依次經(jīng)過(guò)上述的階段。因此,才會(huì)早于執(zhí)行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任務(wù)(Synchronous) 在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù) ...

    wanghui 評(píng)論0 收藏0
  • JS JavaScript事件循環(huán)機(jī)制

    摘要:事件循環(huán)機(jī)制首先區(qū)分進(jìn)程和線程進(jìn)程是資源分配的最小單位系統(tǒng)會(huì)給它分配內(nèi)存不同的進(jìn)程之間是可以同學(xué)的,如管道命名管道消息隊(duì)列一個(gè)進(jìn)程里有單個(gè)或多個(gè)線程瀏覽器是多進(jìn)程的,因?yàn)橄到y(tǒng)給它的進(jìn)程分配了資源內(nèi)存打開(kāi)會(huì)有一個(gè)主進(jìn)程,每打開(kāi)一個(gè)頁(yè)就有一個(gè)獨(dú) JS JavaScript事件循環(huán)機(jī)制 首先區(qū)分進(jìn)程和線程 進(jìn)程是cpu資源分配的最小單位(系統(tǒng)會(huì)給它分配內(nèi)存) 不同的進(jìn)程之間是可以同學(xué)的,如...

    dantezhao 評(píng)論0 收藏0
  • JS與Node.js中的事件循環(huán)

    摘要:的單線程,與它的用途有關(guān)。特點(diǎn)的顯著特點(diǎn)異步機(jī)制事件驅(qū)動(dòng)。隊(duì)列的讀取輪詢線程,事件的消費(fèi)者,的主角。它將不同的任務(wù)分配給不同的線程,形成一個(gè)事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 這兩天跟同事同事討論遇到的一個(gè)問(wèn)題,js中的event loop,引出了chrome與node中運(yùn)行具有setTimeout和Promise的程序時(shí)候執(zhí)行結(jié)果不一樣的問(wèn)題,從而引出了Nodejs的...

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

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

0條評(píng)論

閱讀需要支付1元查看
<