AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁(yè) > 科技  > 軟件

EventLoop = TaskQueue + RenderQueue,你看明白了嗎?

來(lái)源: 責(zé)編: 時(shí)間:2023-12-08 09:13:38 265觀看
導(dǎo)讀前言在最近的工作和學(xué)習(xí)中,有一個(gè)詞總是在眼前揮之不去--EventLoop。而在之前,其實(shí)我們講過(guò)相關(guān)的內(nèi)容,Event Loop 可視化解析圖片上文我們從偏JS調(diào)用機(jī)制的角度分析了,調(diào)用棧(Call Stack)/宏任務(wù)隊(duì)列 (Task Queue)和微任

前言

在最近的工作和學(xué)習(xí)中,有一個(gè)詞總是在眼前揮之不去--EventLoop。而在之前,其實(shí)我們講過(guò)相關(guān)的內(nèi)容,Event Loop 可視化解析rsZ28資訊網(wǎng)——每日最新資訊28at.com

Event Loop圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

上文我們從偏JS調(diào)用機(jī)制的角度分析了,調(diào)用棧(Call Stack)/宏任務(wù)隊(duì)列 (Task Queue)和微任務(wù)隊(duì)列 (Microtask Queue)他們之間的關(guān)系和他們是如何協(xié)同合作的。并且,舉了很多例子,用可視化的方式講解它們?nèi)绾喂ぷ鞯摹?span style="display:none">rsZ28資訊網(wǎng)——每日最新資訊28at.com

而今天,我們從瀏覽器內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)來(lái)談?wù)凟ventLoop是如何從接受任務(wù)到渲染出對(duì)應(yīng)頁(yè)面的。rsZ28資訊網(wǎng)——每日最新資訊28at.com

也就是下圖中所涉及到的各個(gè)重要節(jié)點(diǎn)。在閱讀完本文后,希望大家能對(duì)下面有一個(gè)清晰的認(rèn)知。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

好了,天不早了,干點(diǎn)正事哇。rsZ28資訊網(wǎng)——每日最新資訊28at.com

我們能所學(xué)到的知識(shí)點(diǎn)

  1. 前置知識(shí)點(diǎn)
  2. 事件循環(huán)(Event Loop)
  3. 任務(wù)隊(duì)列/微任務(wù)隊(duì)列/調(diào)用棧
  4. 在渲染隊(duì)列中執(zhí)行的是什么?
  5. EventLoop模型

1. 前置知識(shí)點(diǎn)

「前置知識(shí)點(diǎn)」,只是做一個(gè)概念的介紹,不會(huì)做深度解釋。因?yàn)椋@些概念在下面文章中會(huì)有出現(xiàn),為了讓行文更加的順暢,所以將本該在文內(nèi)的概念解釋放到前面來(lái)。「如果大家對(duì)這些概念熟悉,可以直接忽略」同時(shí),由于閱讀我文章的群體有很多,所以有些知識(shí)點(diǎn)可能「我視之若珍寶,爾視只如草芥,棄之如敝履」。以下知識(shí)點(diǎn),請(qǐng)「酌情使用」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

頁(yè)面刷新術(shù)語(yǔ)

我們?cè)陧?yè)面是如何生成的(宏觀角度)一文中提到過(guò)這些指標(biāo),這里就拿來(lái)主義了。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 「屏幕刷新頻率」

一秒內(nèi)屏幕刷新的次數(shù)(一秒內(nèi)顯示了多少幀的圖像),單位 Hz(赫茲),如常見(jiàn)的 60 Hz。「刷新頻率取決于硬件的固定參數(shù)」(不會(huì)變的)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 「逐行掃描」
  • 顯示器并不是一次性將畫(huà)面顯示到屏幕上,而是「從左到右邊,從上到下逐行掃描」,順序顯示整屏的一個(gè)個(gè)像素點(diǎn),不過(guò)這一過(guò)程快到人眼無(wú)法察覺(jué)到變化。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 以 60 Hz 刷新率的屏幕為例,這一過(guò)程即 1000 / 60 ≈ 16ms。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 當(dāng)掃描完一個(gè)屏幕后,設(shè)備需要「重新回到第一行」以進(jìn)入下一次的循環(huán),此時(shí)有一段時(shí)間空隙,稱為VerticalBlanking Interval(VBI)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 「幀率 (Frame Rate)」rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 表示 「GPU 在一秒內(nèi)繪制操作的幀數(shù)」,如 60 fps,即每秒鐘GPU最多繪制 60 幀畫(huà)面。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 幀率是「動(dòng)態(tài)變化」的,例如當(dāng)畫(huà)面靜止時(shí),GPU 是沒(méi)有繪制操作的,屏幕刷新的還是buffer中的數(shù)據(jù),即GPU最后操作的幀數(shù)據(jù)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 「畫(huà)面撕裂(tearing)」rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 一個(gè)屏幕內(nèi)的數(shù)據(jù)來(lái)自2個(gè)不同的幀,畫(huà)面會(huì)出現(xiàn)撕裂感。rsZ28資訊網(wǎng)——每日最新資訊28at.com

測(cè)試幀率

我們可以借助requestAnimationFrame通過(guò)每個(gè)測(cè)量前后幀發(fā)生的時(shí)間間隔,來(lái)從側(cè)面查看本地瀏覽器幀率。rsZ28資訊網(wǎng)——每日最新資訊28at.com

const checkRequestAnimationDiff = () => {    let prev;    function call() {        requestAnimationFrame((timestamp) => {            if (prev) {                console.log(timestamp - prev);                 // 應(yīng)該大約是60FPS的16.6毫秒            }            prev = timestamp;            call();        });    }    call();}checkRequestAnimationDiff();

隨意打開(kāi)一個(gè)網(wǎng)站,并將上述代碼貼到devtool-Console運(yùn)行。rsZ28資訊網(wǎng)——每日最新資訊28at.com

下面是,我們?cè)赗eact-官網(wǎng)[1]中實(shí)驗(yàn)的結(jié)果。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

從輸出結(jié)果來(lái)看,雖然結(jié)果不是唯一,但是它們的值都穩(wěn)定在16.67~16.68。和我們60fps是吻合的。rsZ28資訊網(wǎng)——每日最新資訊28at.com

WebAPI

WebAPI工作的原理依賴于瀏覽器作為宿主環(huán)境來(lái)提供和執(zhí)行這些API。在Web開(kāi)發(fā)中,我們通常指的WebAPI是「瀏覽器內(nèi)置的API」,它們?cè)试S開(kāi)發(fā)者利用JavaScript與瀏覽器的功能進(jìn)行交互。rsZ28資訊網(wǎng)——每日最新資訊28at.com

APIsrsZ28資訊網(wǎng)——每日最新資訊28at.com

描述rsZ28資訊網(wǎng)——每日最新資訊28at.com

網(wǎng)絡(luò)請(qǐng)求rsZ28資訊網(wǎng)——每日最新資訊28at.com

(Network Requests)rsZ28資訊網(wǎng)——每日最新資訊28at.com

使用XMLHttpRequestfetch API,可以發(fā)起異步的HTTP請(qǐng)求到服務(wù)器,并在不刷新頁(yè)面的情況下獲取或發(fā)送數(shù)據(jù)。rsZ28資訊網(wǎng)——每日最新資訊28at.com


rsZ28資訊網(wǎng)——每日最新資訊28at.com

DOM操作rsZ28資訊網(wǎng)——每日最新資訊28at.com

(DOM Manipulation)rsZ28資訊網(wǎng)——每日最新資訊28at.com

瀏覽器提供了一套DOM API,允許JavaScript訪問(wèn)和操作頁(yè)面上的元素。比如,可以添加、刪除或更改元素,或者修改元素的樣式和內(nèi)容。rsZ28資訊網(wǎng)——每日最新資訊28at.com

事件處理rsZ28資訊網(wǎng)——每日最新資訊28at.com

(Event Handling)rsZ28資訊網(wǎng)——每日最新資訊28at.com

WebAPI允許注冊(cè)事件處理程序來(lái)響應(yīng)用戶行為(如點(diǎn)擊、滑動(dòng))或?yàn)g覽器事件(如頁(yè)面加載、窗口尺寸變化)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

存儲(chǔ)機(jī)制rsZ28資訊網(wǎng)——每日最新資訊28at.com

(Storage Mechanisms)rsZ28資訊網(wǎng)——每日最新資訊28at.com

瀏覽器提供了如localStoragesessionStorageIndexedDB等API,可以在用戶的設(shè)備上存儲(chǔ)數(shù)據(jù)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

設(shè)備APIrsZ28資訊網(wǎng)——每日最新資訊28at.com

(Device APIs)rsZ28資訊網(wǎng)——每日最新資訊28at.com

可以訪問(wèn)設(shè)備的硬件,如攝像頭、麥克風(fēng)、地理位置等,這通常通過(guò)navigator對(duì)象暴露的API實(shí)現(xiàn)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖形和動(dòng)畫(huà)rsZ28資訊網(wǎng)——每日最新資訊28at.com

(Graphics & Animation)rsZ28資訊網(wǎng)——每日最新資訊28at.com

CanvasWebGL API允許在網(wǎng)頁(yè)上繪制二維和三維圖形。requestAnimationFrame為動(dòng)畫(huà)提供了一個(gè)優(yōu)化的循環(huán)機(jī)制。rsZ28資訊網(wǎng)——每日最新資訊28at.com

性能監(jiān)控rsZ28資訊網(wǎng)——每日最新資訊28at.com

(Performance Monitoring)rsZ28資訊網(wǎng)——每日最新資訊28at.com

Performance API提供了獲取瀏覽器性能相關(guān)數(shù)據(jù)的接口,幫助開(kāi)發(fā)者監(jiān)控和優(yōu)化網(wǎng)頁(yè)性能。rsZ28資訊網(wǎng)——每日最新資訊28at.com

其他APIrsZ28資訊網(wǎng)——每日最新資訊28at.com

(Other APIs)rsZ28資訊網(wǎng)——每日最新資訊28at.com

還有諸如Web Audio APIWebRTCWebSocket等,使得在網(wǎng)頁(yè)上實(shí)現(xiàn)復(fù)雜的音頻處理、實(shí)時(shí)通信成為可能。rsZ28資訊網(wǎng)——每日最新資訊28at.com

WebAPI的工作流程

  1. 「調(diào)用API」:開(kāi)發(fā)者在JavaScript代碼中調(diào)用某個(gè)WebAPI。
  2. 「瀏覽器解釋執(zhí)行」: 瀏覽器解釋JavaScript代碼,并「執(zhí)行相應(yīng)的API調(diào)用」。
  3. 「API內(nèi)部處理」:WebAPI內(nèi)部可能會(huì)執(zhí)行多種操作,如觸發(fā)網(wǎng)絡(luò)請(qǐng)求、訪問(wèn)數(shù)據(jù)庫(kù)、啟動(dòng)硬件設(shè)備等。
  4. 「回調(diào)和事件循環(huán)」:對(duì)于異步操作,WebAPI通常會(huì)使用回調(diào)函數(shù)或Promise來(lái)處理操作完成后的結(jié)果。瀏覽器的事件循環(huán)機(jī)制確保了這些回調(diào)在適當(dāng)?shù)臅r(shí)候被調(diào)用。
  5. 「渲染和更新」:對(duì)于涉及視覺(jué)變化的API,如DOM操作或Canvas繪圖,瀏覽器會(huì)更新頁(yè)面內(nèi)容,這通常發(fā)生在瀏覽器的下一個(gè)重繪周期。

在整個(gè)過(guò)程中,「瀏覽器的角色是中介」,它提供了執(zhí)行API的環(huán)境和必要的安全措施。這些API讓W(xué)eb應(yīng)用可以像本地應(yīng)用一樣豐富和強(qiáng)大,同時(shí)仍然運(yùn)行在瀏覽器這個(gè)相對(duì)安全的沙箱環(huán)境中。rsZ28資訊網(wǎng)——每日最新資訊28at.com

下面的圖,展示了WebAPI的地位(中間部分)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

GPU硬件加速

「GPU(Graphics Processing Unit)硬件加速」是一種利用GPU來(lái)執(zhí)行圖形和計(jì)算任務(wù)的技術(shù)。在Web開(kāi)發(fā)中,GPU硬件加速可以通過(guò)利用用戶計(jì)算機(jī)中的GPU資源來(lái)加速瀏覽器的渲染和繪制操作。這通常可以提高網(wǎng)頁(yè)的性能和流暢度,尤其是對(duì)于需要大量圖形操作的頁(yè)面。rsZ28資訊網(wǎng)——每日最新資訊28at.com

在Web開(kāi)發(fā)中,一些CSS屬性和操作可以觸發(fā)GPU硬件加速,以便更有效地利用GPU資源。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. 3D 變換(transform)

使用transform屬性進(jìn)行3D變換,如translate3d、rotate3d、scale3d等,可以觸發(fā)GPU硬件加速。例如:rsZ28資訊網(wǎng)——每日最新資訊28at.com

.element {  transform: translate3d(0, 0, 0);}
  1. CSS 動(dòng)畫(huà)(animation)和過(guò)渡(transition):
  • 使用CSS動(dòng)畫(huà)和過(guò)渡屬性,例如transform屬性的過(guò)渡,可以觸發(fā)GPU硬件加速。例如:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    .element {  transition: transform 0.3s ease-in-out;}

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    Canvas 繪圖:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 在<canvas>元素上進(jìn)行繪圖操作通常會(huì)利用GPU硬件加速。這包括使用2D或WebGL上下文進(jìn)行圖形渲染。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    使用 will-change 屬性:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • will-change屬性告訴瀏覽器某個(gè)屬性將會(huì)被改變,從而可以提前進(jìn)行優(yōu)化。例如:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    .element {  will-change: transform;}

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    使用 image-rendering 屬性:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • image-rendering屬性用于指定圖像的渲染質(zhì)量,而且在某些情況下也能觸發(fā)GPU硬件加速。例如:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    .element {  image-rendering: pixelated;}

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    使用 backface-visibility 屬性:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • backface-visibility屬性用于指定當(dāng)元素不面向屏幕時(shí)是否可見(jiàn)。在某些情況下,該屬性的使用可以觸發(fā)GPU硬件加速。例如:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    .element {  backface-visibility: hidden;}

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    使用 filter 屬性(某些情況下):rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 在某些情況下,使用filter屬性(如模糊、對(duì)比度等)可能觸發(fā)GPU硬件加速。rsZ28資訊網(wǎng)——每日最新資訊28at.com

還記得我們?cè)谀銜?huì)在瀏覽器中打斷點(diǎn)嗎?我會(huì)!中介紹過(guò)如何看chromium 在線倉(cāng)庫(kù)[2]rsZ28資訊網(wǎng)——每日最新資訊28at.com

那我們就從源碼的角度來(lái)看看,為什么上面的屬性會(huì)走GPU硬件加速rsZ28資訊網(wǎng)——每日最新資訊28at.com

或者我們可以看compositing_reason_finder.cc這個(gè)文件,它例舉了很多枚舉類型。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

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

事件循環(huán)就是一個(gè)「死循環(huán)」,不死不休。rsZ28資訊網(wǎng)——每日最新資訊28at.com

舊的操作系統(tǒng)不支持多線程,它們的事件循環(huán)可以被大致描述為一個(gè)簡(jiǎn)單的循環(huán):rsZ28資訊網(wǎng)——每日最新資訊28at.com

while (true) {    if (hasTasks()) {        executeTask();    }}

現(xiàn)代操作系統(tǒng)的調(diào)度器(schedulers)非常復(fù)雜。它們有優(yōu)先級(jí)設(shè)置、執(zhí)行隊(duì)列等許多其他技術(shù)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

這里做一個(gè)題外話,看到schedulers/優(yōu)先級(jí)設(shè)置是不是想到React-Fiber架構(gòu)了。其實(shí),React在內(nèi)部就是模仿操作系統(tǒng),做了自己的實(shí)現(xiàn)邏輯。(這里就不展開(kāi)說(shuō)明了)rsZ28資訊網(wǎng)——每日最新資訊28at.com

為了讓事情簡(jiǎn)單化,我們可以將事件循環(huán)(Event Loop)描述為一個(gè)循環(huán),該循環(huán)檢查是否有任何待處理的任務(wù):rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com


任務(wù)觸發(fā)器

瀏覽器屬于「事件驅(qū)動(dòng)」的技術(shù)框架,如果想讓Event Loop探查并執(zhí)行對(duì)應(yīng)的任務(wù),首先要做的就是將某些任務(wù)進(jìn)行觸發(fā)。也就是喚起指定任務(wù)的觸發(fā)器。rsZ28資訊網(wǎng)——每日最新資訊28at.com

下面就是我們平時(shí)能夠接觸到的任務(wù)觸發(fā)器rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. 「<script>標(biāo)簽」:通過(guò)HTML的<script>標(biāo)簽引入的代碼會(huì)被瀏覽器解析并執(zhí)行,相關(guān)的同步任務(wù)會(huì)被放入事件循環(huán)中。
  2. 「延后的任務(wù)」:

setTimeout:設(shè)置一個(gè)計(jì)時(shí)器,在指定的延時(shí)后執(zhí)行一段代碼。rsZ28資訊網(wǎng)——每日最新資訊28at.com

setInterval:設(shè)置一個(gè)計(jì)時(shí)器,按照指定的時(shí)間間隔重復(fù)執(zhí)行一段代碼。rsZ28資訊網(wǎng)——每日最新資訊28at.com

requestIdleCallback:安排一個(gè)函數(shù)在瀏覽器空閑時(shí)期被調(diào)用。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. 「瀏覽器API的事件處理程序」:

用戶觸發(fā)的事件,例如click, mousedown, input, blur等。rsZ28資訊網(wǎng)——每日最新資訊28at.com

代碼生成的事件,比如XMLHttpRequest的響應(yīng)處理、fetch API的promise resolve等。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    「Promise狀態(tài)變化」:當(dāng)一個(gè)Promise對(duì)象的狀態(tài)改變時(shí)(例如從pending變?yōu)閒ulfilled或rejected),相關(guān)的任務(wù)會(huì)被加入事件循環(huán)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

  2. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    「觀察者」:rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

DOMMutationObserver:用于觀察DOM變動(dòng),當(dāng)DOM發(fā)生變化時(shí)可以通知應(yīng)用。rsZ28資訊網(wǎng)——每日最新資訊28at.com

IntersectionObserver:用于觀察元素是否進(jìn)入了父元素或視口的特定區(qū)域。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. rsZ28資訊網(wǎng)——每日最新資訊28at.com

    requestAnimationFrame:用于在「下一次重新渲染前」執(zhí)行動(dòng)畫(huà)或視覺(jué)更新的函數(shù),使動(dòng)畫(huà)流暢。rsZ28資訊網(wǎng)——每日最新資訊28at.com

    rsZ28資訊網(wǎng)——每日最新資訊28at.com

上面的任務(wù)幾乎都是通過(guò)WebAPI進(jìn)行觸發(fā)的。rsZ28資訊網(wǎng)——每日最新資訊28at.com

例如,我們?cè)诖a中有這樣一行:setTimeout(function a() {}, 100)。當(dāng)我們執(zhí)行setTimeout時(shí),WebAPI將任務(wù)延遲了100毫秒。100毫秒后,WebAPI將函數(shù)a()放入任務(wù)隊(duì)列(Task Queue)(也可以稱為Callback Queue)中。事件循環(huán)在下一個(gè)循環(huán)中獲取該任務(wù)并執(zhí)行它。rsZ28資訊網(wǎng)——每日最新資訊28at.com

JS執(zhí)行和頁(yè)面渲染是難兄難弟

EventLoop = TaskQueue + RenderQueuersZ28資訊網(wǎng)——每日最新資訊28at.com

在之前的文章中,我們提到過(guò)文檔對(duì)象模型(DOM)是一個(gè)應(yīng)用編程接口(API),通過(guò)創(chuàng)建表示文檔的樹(shù),以一種「獨(dú)立于平臺(tái)和語(yǔ)言」的方式訪問(wèn)和修改一個(gè)頁(yè)面的內(nèi)容和結(jié)構(gòu)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

在HTML文檔中,Web開(kāi)發(fā)者可以使用JS來(lái)CRUD DOM 結(jié)構(gòu),其主要的目的是「動(dòng)態(tài)」改變HTML文檔的結(jié)構(gòu)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 讀取DOM元素的數(shù)據(jù):大小、屬性、位置等
  • 改變屬性:data-屬性、寬度、高度、位置、CSS屬性等
  • 創(chuàng)建/刪除HTML節(jié)點(diǎn)

而在JS把玩DOM之后,就將其扔給了瀏覽器的渲染引擎,而渲染引擎任勞任怨的處理DOM和DOM攜帶的附帶信息,并將其渲染成用戶心儀的頁(yè)面。rsZ28資訊網(wǎng)——每日最新資訊28at.com

也就是說(shuō)「JS和瀏覽器(渲染引擎)都能染指過(guò)DOM」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

基于上面的特定的背景,我們可以得出一個(gè)結(jié)論,執(zhí)行JS和渲染頁(yè)面都在同一個(gè)線程里。rsZ28資訊網(wǎng)——每日最新資訊28at.com

這意味著事件循環(huán)包含渲染流程。而渲染流程不是單一的操作。其實(shí),它是渲染隊(duì)列:rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

現(xiàn)在EventLoop處理鏈路上有兩個(gè)任務(wù)源。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. JS任務(wù) - SomeJsTasks
  2. 渲染任務(wù) - RenderQueue

屏幕更新

對(duì)于瀏覽器來(lái)說(shuō),事件循環(huán)與幀(frames)密切相關(guān),因?yàn)镋ventLoop同時(shí)執(zhí)行JS代碼并渲染頁(yè)面。rsZ28資訊網(wǎng)——每日最新資訊28at.com

可以將幀視為屏幕狀態(tài)的快照,即用戶在某一時(shí)刻看到的畫(huà)面。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

我們?cè)贑hromium 最新渲染引擎--RenderingNG也介紹過(guò)frames。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

瀏覽器的目標(biāo)是盡快顯示頁(yè)面更新,考慮到硬件和軟件的限制:rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 硬件限制:屏幕刷新率
  • 軟件限制:操作系統(tǒng)設(shè)置、瀏覽器及其設(shè)置、節(jié)能設(shè)置等

絕大多數(shù)瀏覽器/操作系統(tǒng)支持60幀每秒(Frames Per Second,F(xiàn)PS)。瀏覽器試圖以這個(gè)特定的速率更新屏幕。rsZ28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)我們使用60 FPS時(shí),這意味著瀏覽器在必須「渲染新幀之前有16.6毫秒的時(shí)間段來(lái)執(zhí)行任務(wù)」(1000/60),而渲染新幀也會(huì)消耗時(shí)間。rsZ28資訊網(wǎng)——每日最新資訊28at.com

3. 任務(wù)隊(duì)列/微任務(wù)隊(duì)列/調(diào)用棧

瀏覽器使用兩個(gè)隊(duì)列來(lái)執(zhí)行我們的JS代碼:rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 任務(wù)隊(duì)列(TaskQueue)或宏任務(wù)隊(duì)列專用于所有事件、延遲任務(wù)等。
  • 微任務(wù)隊(duì)列(Microtask Queue)用于處理 promise 回調(diào)(已解決和已拒絕),以及 MutationObserver。這個(gè)隊(duì)列中的單個(gè)元素被稱為 微任務(wù)。

任務(wù)隊(duì)列(Task Queue)

當(dāng)瀏覽器收到一個(gè)新任務(wù)時(shí),它將任務(wù)放入任務(wù)隊(duì)列。每個(gè)事件循環(huán)定期從任務(wù)隊(duì)列中獲取任務(wù)并執(zhí)行它。任務(wù)完成后,「如果瀏覽器有時(shí)間(渲染隊(duì)列沒(méi)有任務(wù)),事件循環(huán)從任務(wù)隊(duì)列獲取另一個(gè)任務(wù),直到渲染隊(duì)列接收到任務(wù)為止」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

案例分析1

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

我們有3個(gè)任務(wù):A、B、C。事件循環(huán)獲取并執(zhí)行第一個(gè)任務(wù),花費(fèi)了4毫秒。然后事件循環(huán)檢查其他隊(duì)列(微任務(wù)隊(duì)列和渲染隊(duì)列),它們是空的。事件循環(huán)執(zhí)行任務(wù)B,花費(fèi)了12毫秒。總共兩個(gè)任務(wù)使用了16毫秒。然后瀏覽器將任務(wù)添加到渲染隊(duì)列以繪制新幀。事件循環(huán)檢查渲染隊(duì)列并開(kāi)始執(zhí)行渲染隊(duì)列中的任務(wù),它們大約花費(fèi)1毫秒。完成這些操作后,事件循環(huán)返回到任務(wù)隊(duì)列并執(zhí)行最后一個(gè)任務(wù)C。rsZ28資訊網(wǎng)——每日最新資訊28at.com

事件循環(huán)無(wú)法預(yù)測(cè)任務(wù)將花費(fèi)多少時(shí)間。此外,事件循環(huán)「無(wú)法暫停任務(wù)來(lái)渲染幀」,因?yàn)闉g覽器引擎不知道該任務(wù)是否會(huì)對(duì)繪制內(nèi)容有修改動(dòng)作,還是任務(wù)只是為了渲染幀做了一些無(wú)關(guān)痛癢的準(zhǔn)備工作。rsZ28資訊網(wǎng)——每日最新資訊28at.com

在執(zhí)行JS代碼期間,「JS所做的所有更改并不會(huì)直接呈現(xiàn)給用戶,而是等到宏任務(wù)和所有待處理的微任務(wù)完成后才會(huì)表現(xiàn)出來(lái)」。但是,此時(shí)在JS中可以獲取到最新DOM的變更信息。rsZ28資訊網(wǎng)——每日最新資訊28at.com

案例分析2

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

隊(duì)列中只有2個(gè)任務(wù)(A、B)。第一個(gè)任務(wù)A花費(fèi)了240毫秒(無(wú)法中斷)。由于60FPS意味著每16.6毫秒應(yīng)該渲染一幀,所以瀏覽器有14幀的空窗期。當(dāng)任務(wù)A結(jié)束時(shí),事件循環(huán)執(zhí)行渲染隊(duì)列中的任務(wù)以繪制新幀。rsZ28資訊網(wǎng)——每日最新資訊28at.com

「盡管我們失去了14幀,這并不意味著我們將連續(xù)渲染15幀。它只會(huì)渲染最后一幀」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

這就是當(dāng)JS中有長(zhǎng)任務(wù)執(zhí)行時(shí),會(huì)阻塞頁(yè)面的渲染,如果這14幀中間操作了過(guò)多的DOM,頁(yè)面中就會(huì)有一種從第一幀到第十五幀的跳動(dòng)。這就是為什么我們總是要將長(zhǎng)任務(wù)拆分成很多小任務(wù)的原因。rsZ28資訊網(wǎng)——每日最新資訊28at.com

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

在Event Loop 可視化解析講解中我們對(duì)調(diào)用棧有過(guò)介紹。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

案例分析

function D() {  debugger;  console.log('前端柒八九');}function C() {  D();}function B() {  C();  }function other() {   // 不在我們考察堆棧上下文中}function A() {  const arr = [];  while (arr.length < 2) {    arr.push(other());  }  B();}console.log(A());

將上面的代碼貼到devTool-Console或者devTool-Source-Snippet中執(zhí)行。這段代碼將在debugger處暫停。rsZ28資訊網(wǎng)——每日最新資訊28at.com

這里多提一嘴,關(guān)于如何在瀏覽器中優(yōu)雅的調(diào)試斷點(diǎn),可以參考你會(huì)在瀏覽器中打斷點(diǎn)嗎?我會(huì)!rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • console.log(A());,它是調(diào)用棧的開(kāi)始。
  • 然后我們進(jìn)入 A 函數(shù),并多次調(diào)用 other。在我們到達(dá)debugger之前,這個(gè)函數(shù)不會(huì)出現(xiàn)在調(diào)用棧中,因?yàn)樗谖覀兊竭_(dá)調(diào)試器之前就結(jié)束了。

這是我們?cè)赿ebugger停止時(shí)調(diào)用棧的樣子:rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖中(anonymous)表示全局作用域,我們沒(méi)貼出來(lái),它就是指向25行調(diào)用棧的入口的。rsZ28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)調(diào)用棧為空時(shí),「當(dāng)前任務(wù)」完成。rsZ28資訊網(wǎng)——每日最新資訊28at.com

微任務(wù)

微任務(wù)只有兩個(gè)可能的來(lái)源:rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. Promise 回調(diào)(onResolved/onRejected)
  2. MutationObserver 回調(diào)。

微任務(wù)有一個(gè)主要特征,使它們與其他任務(wù)完全不同:rsZ28資訊網(wǎng)——每日最新資訊28at.com

一旦調(diào)用棧為空,微任務(wù)將立即執(zhí)行。rsZ28資訊網(wǎng)——每日最新資訊28at.com

微任務(wù)可以創(chuàng)建其他微任務(wù),「這些微任務(wù)將在調(diào)用棧結(jié)束時(shí)執(zhí)行」。每個(gè)「新的微任務(wù)都會(huì)推遲執(zhí)行新的宏任務(wù)或新幀的渲染」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

案例分析

在這個(gè)例子中,微任務(wù)隊(duì)列中有4個(gè)微任務(wù):rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

要執(zhí)行的第一個(gè)微任務(wù)是A。A花費(fèi)了200毫秒,而且我們?cè)阡秩娟?duì)列中有任務(wù)。然而,它們將被推遲,因?yàn)槲覀內(nèi)匀挥?個(gè)微任務(wù)。這意味著在執(zhí)行A后,事件循環(huán)將執(zhí)行微任務(wù)B、C,最后是D。當(dāng)「微任務(wù)隊(duì)列變空時(shí),事件循環(huán)渲染新幀」。在這個(gè)例子中,這4個(gè)微任務(wù)花費(fèi)了0.5秒。在這段時(shí)間內(nèi),瀏覽器「UI被阻塞,不可交互」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

后續(xù)的微任務(wù)可以阻塞網(wǎng)站UI,使頁(yè)面變得不可交互。rsZ28資訊網(wǎng)——每日最新資訊28at.com

這個(gè)微任務(wù)特性既可能是優(yōu)勢(shì)也可能是劣勢(shì)。例如,當(dāng) MutationObserver 根據(jù)DOM更改調(diào)用其回調(diào)時(shí),用戶在回調(diào)完成之前看不到頁(yè)面上的更改。因此,我們可以有效地管理用戶看到的內(nèi)容。rsZ28資訊網(wǎng)——每日最新資訊28at.com

更新后的事件循環(huán)圖示:rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

各自的特性

  • 調(diào)用棧是用于跟蹤「正在被執(zhí)行」函數(shù)的機(jī)制,而宏任務(wù)隊(duì)列是用于跟蹤「將要被執(zhí)行」函數(shù)的機(jī)制。
  • 宏任務(wù)隊(duì)列和微任務(wù)隊(duì)列都是「FIFO」(先進(jìn)先出)的隊(duì)列結(jié)構(gòu),這些任務(wù)是「同步阻塞」的

4. 在渲染隊(duì)列中執(zhí)行的是什么?

其實(shí),在瀏覽器中渲染頁(yè)面是有很多步驟的。rsZ28資訊網(wǎng)——每日最新資訊28at.com

同時(shí)還涉及多個(gè)進(jìn)程之間的通信。這在之前的頁(yè)面是如何生成的(宏觀角度)有過(guò)介紹,這里就不在羅嗦了。rsZ28資訊網(wǎng)——每日最新資訊28at.com

而今天呢,我們從瀏覽器渲染幀的角度來(lái)看到底發(fā)生了啥?!其實(shí)幀渲染不是一個(gè)單一的操作,它有幾個(gè)階段,每個(gè)階段都可以分為子階段。rsZ28資訊網(wǎng)——每日最新資訊28at.com

新幀渲染的基本結(jié)構(gòu)rsZ28資訊網(wǎng)——每日最新資訊28at.com

RequestAnimationFrame(RAF)

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

requestAnimationFrame 是一個(gè)由瀏覽器提供的 JavaScript API,用于在下一次「瀏覽器重繪之前」執(zhí)行指定的函數(shù)。這個(gè)函數(shù)通常用于執(zhí)行動(dòng)畫(huà)或其他需要高性能更新的任務(wù),因?yàn)樗鼤?huì)在瀏覽器的繪制周期內(nèi)運(yùn)行,以確保動(dòng)畫(huà)的平滑流暢。rsZ28資訊網(wǎng)——每日最新資訊28at.com

特點(diǎn)

  1. 「與瀏覽器的重繪同步:」 requestAnimationFrame 的執(zhí)行時(shí)機(jī)與瀏覽器的重繪周期相同,通常是每秒60次(60幀每秒),這確保了動(dòng)畫(huà)的流暢性。
  2. 「自動(dòng)暫停:」 當(dāng)用戶切換到其他標(biāo)簽頁(yè)或最小化瀏覽器時(shí),requestAnimationFrame 會(huì)自動(dòng)暫停,從而節(jié)省系統(tǒng)資源。
  3. 「避免卡頓:」 由于與瀏覽器的繪制同步,requestAnimationFrame 可以避免由于連續(xù)執(zhí)行任務(wù)導(dǎo)致的卡頓和性能問(wèn)題。
  4. RAF的回調(diào)有一個(gè)DOMHighResTimeStamp參數(shù),它是自時(shí)間起源[3]以來(lái)經(jīng)過(guò)的毫秒數(shù),即文檔生命周期的開(kāi)始。我們不需要在回調(diào)中使用performance.now();
  5. RAF返回一個(gè)描述符(id),因此你可以使用cancelAnimationFrame取消RAF回調(diào)(就像使用setTimeout一樣);
  6. 更改元素大小或讀取元素屬性的JS代碼會(huì)強(qiáng)制使用requestAnimationFrame;

樣式重新計(jì)算(Recalc Style)

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

瀏覽器重新計(jì)算應(yīng)用的樣式。此步驟還會(huì)計(jì)算哪些媒體查詢將處于活動(dòng)狀態(tài)。rsZ28資訊網(wǎng)——每日最新資訊28at.com

以下操作能觸發(fā)重新計(jì)算包括rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 直接更改,比如 a.styles.left = '10px'
  • 通過(guò)CSS文件描述的更改,比如 element.classList.add('my-styles-class')。

此過(guò)程可能觸發(fā)整個(gè)DOM樹(shù)的整體計(jì)算也可以是局部小范圍的計(jì)算過(guò)程,取決于「被改動(dòng)的元素的位置」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 例如,改動(dòng)body元素的屬性,就會(huì)發(fā)生整個(gè)DOM樹(shù)的重新計(jì)算。

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

將元素樣式和DOM元素結(jié)合起來(lái),就會(huì)生成Render TreersZ28資訊網(wǎng)——每日最新資訊28at.com

我們可以通過(guò)devTool-Performance來(lái)檢測(cè)網(wǎng)站在這步所花費(fèi)的時(shí)間。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

React官網(wǎng)-樣式重新計(jì)算所花費(fèi)時(shí)間rsZ28資訊網(wǎng)——每日最新資訊28at.com

布局(Layout)

計(jì)算每個(gè)「可視元素」的位置信息(距離視口的距離和元素本身大小)。并生成對(duì)應(yīng)的Layout Tree。 頁(yè)面上的DOM元素越多,操作就越復(fù)雜。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

React官網(wǎng)-布局所花費(fèi)時(shí)間React官網(wǎng)-布局所花費(fèi)時(shí)間rsZ28資訊網(wǎng)——每日最新資訊28at.com

觸發(fā)條件

對(duì)于現(xiàn)今「富應(yīng)用」來(lái)講,做頁(yè)面中做元素的移動(dòng)和變更那是家常便飯。以下操作就會(huì)觸發(fā)對(duì)應(yīng)的布局流程rsZ28資訊網(wǎng)——每日最新資訊28at.com

  • 讀取與元素的大小和位置相關(guān)的屬性(offsetWidth、offsetLeft、getBoundingClientRect等)。
  • 寫(xiě)入與元素的大小和位置相關(guān)的屬性,除了某些屬性(例如 transform 和 will-change)。

這里,我們用一點(diǎn)篇幅來(lái)講一下為何transform/will-change能跳過(guò)布局階段,直接進(jìn)入合成階段。rsZ28資訊網(wǎng)——每日最新資訊28at.com

在之前的Chromium 最新渲染引擎--RenderingNG我們講過(guò),在渲染流程的最開(kāi)始其實(shí)是還有一個(gè)步驟叫做animate。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

在渲染流程的圖中,用不同顏色來(lái)標(biāo)識(shí)該階段可能會(huì)被不同的線程或者進(jìn)程所執(zhí)行。rsZ28資訊網(wǎng)——每日最新資訊28at.com

顏色rsZ28資訊網(wǎng)——每日最新資訊28at.com

所在進(jìn)程/線程rsZ28資訊網(wǎng)——每日最新資訊28at.com

綠色rsZ28資訊網(wǎng)——每日最新資訊28at.com

渲染進(jìn)程中的主線程rsZ28資訊網(wǎng)——每日最新資訊28at.com

黃色rsZ28資訊網(wǎng)——每日最新資訊28at.com

渲染進(jìn)程中的合成線程rsZ28資訊網(wǎng)——每日最新資訊28at.com

橘色rsZ28資訊網(wǎng)——每日最新資訊28at.com

viz進(jìn)程(也叫GPU進(jìn)程)rsZ28資訊網(wǎng)——每日最新資訊28at.com

在某些階段,可能會(huì)被多個(gè)地方所執(zhí)行,所以該階段可能存在多個(gè)顏色。rsZ28資訊網(wǎng)——每日最新資訊28at.com

而animate存在兩個(gè)顏色(綠色和黃色)也就是這一步,會(huì)在多個(gè)地方被執(zhí)行。rsZ28資訊網(wǎng)——每日最新資訊28at.com

而讓animate能夠在黃色階段,也就是在合成線程中執(zhí)行,就是我們使用了一些CSS3屬性rsZ28資訊網(wǎng)——每日最新資訊28at.com

  1. transform
  2. opacity
  3. filter
  4. will-change

使用了這些屬性后,會(huì)跳過(guò)前面很多的步驟,例如重新計(jì)算樣式/布局/重繪等階段。并且,在合成線程進(jìn)行數(shù)據(jù)轉(zhuǎn)換后,開(kāi)啟GPU的「硬件加速」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

就這速度,你說(shuō)能不快嗎。rsZ28資訊網(wǎng)——每日最新資訊28at.com

其實(shí),上面的內(nèi)容在大部分教程中,都是一種鐵打不動(dòng)的定律。使用了transform/will-change開(kāi)啟了GPU硬件加速,所以性能提升了。rsZ28資訊網(wǎng)——每日最新資訊28at.com

強(qiáng)制布局

強(qiáng)制布局(Forced Synchronous Layout 或 Forced Reflow)是Web性能優(yōu)化領(lǐng)域的一個(gè)術(shù)語(yǔ),它指的是瀏覽器在能夠繼續(xù)「處理后續(xù)操作之前,必須完成當(dāng)前的布局計(jì)算」。rsZ28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)強(qiáng)制執(zhí)行布局時(shí),瀏覽器會(huì)暫停JS主線程,盡管調(diào)用棧不是空的。rsZ28資訊網(wǎng)——每日最新資訊28at.com

有很多我們耳熟能詳?shù)牟僮鳎紩?huì)觸發(fā)強(qiáng)制布局。rsZ28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片rsZ28資訊網(wǎng)——每日最新資訊28at.com

想了解更多

本文鏈接:http://www.tebozhan.com/showinfo-26-39500-0.htmlEventLoop = TaskQueue + RenderQueue,你看明白了嗎?

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 為什么不能通過(guò)GetProcAddress調(diào)用CreateWindow?

下一篇: .NET Core 3.1 升級(jí)到 .NET 8,看看都有哪些變化

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top