<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JS阻塞渲染,這么多年我理解錯(cuò)啦?

          共 1755字,需瀏覽 4分鐘

           ·

          2022-04-27 23:39

          作者:卡頌

          簡(jiǎn)介:《React技術(shù)揭秘》作者

          來(lái)源:SegmentFault  思否社區(qū) 


          大家好,我卡頌。

          在中文社區(qū),這么多年一直流傳一個(gè)說(shuō)法:

          JS線程負(fù)責(zé)執(zhí)行JS,GUI渲染線程負(fù)責(zé)渲染,這兩者是互斥的,所以JS執(zhí)行時(shí)會(huì)阻塞渲染。

          但隨著Dev Tools使用的增多,逐漸開始懷疑以上說(shuō)法。本文會(huì)以實(shí)際案例來(lái)解釋為什么JS阻塞渲染。

          到底幾個(gè)線程



          在講解JS線程與GUI線程互斥的文章中,通常會(huì)列出渲染進(jìn)程包含的線程,比如:

          • GUI渲染線程

          • JS引擎線程

          • 事件觸發(fā)線程

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

          • HTTP請(qǐng)求線程



          但是,我們以百度的搜索頁(yè)舉例,打開Performance面板開啟錄制:


          上圖錄制結(jié)果中:

          • Chrome_ChildIOThread對(duì)應(yīng)IO線程的任務(wù)記錄,用戶輸入、網(wǎng)絡(luò)、設(shè)備相關(guān)事件都與他相關(guān)

          • Raster記錄光柵化線程池任務(wù)、GPU記錄GPU合成位圖的任務(wù)、Compositor記錄合成線程的任務(wù)執(zhí)行,以上三者都與瀏覽器渲染相關(guān)

          • Main記錄渲染進(jìn)程的主線程中的任務(wù)


          從這個(gè)角度看,瀏覽器實(shí)際的線程情況與那些GUI線程相關(guān)的文章描述的并不相同。

          主線程的任務(wù)



          接下來(lái),讓我們進(jìn)入Main。紅線框內(nèi)長(zhǎng)短不一的灰色塊,就是主線程中執(zhí)行的任務(wù)。


          注意看紅框內(nèi)的綠色塊FP,代表First Paint(首次繪制):


          那么在首次繪制前都要執(zhí)行什么任務(wù)呢?可以看到主要有3個(gè)Task(任務(wù)):


          第一個(gè)任務(wù)是請(qǐng)求HTML數(shù)據(jù):


          Parse HTML


          當(dāng)請(qǐng)求回HTML字節(jié)流后,開始第二個(gè)任務(wù),將HTML字節(jié)流解析為DOM,這個(gè)任務(wù)的名字就是圖中的藍(lán)色塊Parse HTML


          注意其中有些執(zhí)行時(shí)長(zhǎng)不一的Evaluate Script,這些是解析DOM樹過(guò)程中遇到的JS代碼。

          DOM樹中可以看到這些阻塞DOM樹生成的JS腳本:


          他們的存在顯著拉長(zhǎng)了Parse HTML的用時(shí)。

          Recaculate Style


          解析完DOM樹(藍(lán)色Parse HTML)后,下一個(gè)任務(wù)是紫色Recaculate Style


          他負(fù)責(zé)將HTML中的CSS樣式(外聯(lián)、內(nèi)聯(lián))輸出為styleSheetsstyleSheets有兩個(gè)作用:

          1. 可以與DOM樹結(jié)合為頁(yè)面帶來(lái)樣式

          2. JS可以操作styleSheets改變頁(yè)面樣式


          我們可以從控制臺(tái)打印document.styleSheets直觀感受他的存在:


          Layout


          有了DOM樹與styleSheets,接下來(lái)需要為視圖中可見(jiàn)部分生成一棵樹(比如display: none部分就不需要在這棵樹中顯示)。

          這個(gè)任務(wù)是紫色Layout


          Update Layer Tree


          用戶看到的頁(yè)面實(shí)際是由多層頁(yè)面重疊后的結(jié)果,開發(fā)者可以用很多手段(比如z-index)改變某部分的層級(jí)。

          比如滾動(dòng)條就會(huì)形成自己獨(dú)立的層級(jí):


          既然是多層結(jié)構(gòu),那么就需要更新每層的信息,這個(gè)任務(wù)是紫色的Update Layer Tree


          Paint


          我們可以發(fā)現(xiàn),在FP之前,Update Layer Tree之后只剩下Paint這一任務(wù)了:


          從字面意義講,這就是繪制么?并不是。

          Paint的任務(wù)是整理每一層頁(yè)面的繪制信息,構(gòu)成繪制列表,這些數(shù)據(jù)會(huì)交給合成線程負(fù)責(zé)后續(xù)繪制操作。


          可以發(fā)現(xiàn),具體的繪制操作是交由合成線程完成,他與JS所在線程(主線程)并不是互斥的。

          JS為啥阻塞渲染



          我們現(xiàn)在知道,JS執(zhí)行與Paint任務(wù)都發(fā)生在主線程。

          渲染被阻塞的原因很明顯:因?yàn)?/span>Paint任務(wù)沒(méi)有及時(shí)執(zhí)行,即繪制列表沒(méi)有及時(shí)提交給合成線程。

          之所以沒(méi)有及時(shí)執(zhí)行,可能是因?yàn)?/span>JS執(zhí)行時(shí)間過(guò)長(zhǎng),導(dǎo)致這一幀沒(méi)有時(shí)間執(zhí)行Paint。

          比如,我們打開B站,記錄下主線程的任務(wù)。

          可以看到,有個(gè)JS執(zhí)行時(shí)長(zhǎng)達(dá)到231.88ms,超過(guò)了一幀的時(shí)間,在此期間主線程就沒(méi)時(shí)間執(zhí)行Paint了:


          總結(jié)



          JS之所以阻塞渲染,是因?yàn)?/span>JS執(zhí)行與渲染相關(guān)任務(wù)都在爭(zhēng)奪主線程有限的資源。

          當(dāng)JS執(zhí)行時(shí)間過(guò)長(zhǎng),渲染相關(guān)任務(wù)就沒(méi)時(shí)間執(zhí)行了。



          點(diǎn)擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開更多互動(dòng)和交流,掃描下方”二維碼“或在“公眾號(hào)后臺(tái)回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -


          瀏覽 43
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操操操综合 | 国产淫伦久久久久久久 | 无码视屏| 欧美国产免费A视频 | 国产又爽 又黄 免费网站打游戏 |