渲染模塊在執(zhí)行過(guò)程中會(huì)被劃分為很多子階段扰肌,輸入的HTML經(jīng)過(guò)這些子階段厚柳,最后輸出像素氧枣。我們把這樣的一個(gè)處理流程叫做渲染流水線。
〇别垮、 瀏覽器加載資源
用戶輸入U(xiǎn)RL時(shí)便监,瀏覽器依賴(lài)網(wǎng)絡(luò)模塊加載html、css碳想、js等資源數(shù)據(jù)烧董。
一、 DOM樹(shù)的構(gòu)建
html解析器根據(jù)html文件胧奔,構(gòu)建結(jié)點(diǎn)逊移,生成DOM樹(shù)。
DOM和html的內(nèi)容幾乎一摸一樣龙填,唯一不同的是DOM以樹(shù)結(jié)構(gòu)保存在內(nèi)存中胳泉,可由js修改。
document.getElementsByTagName("p")[0].innerText="black";
二觅够、樣式計(jì)算
樣式計(jì)算的目的是為了計(jì)算出DOM節(jié)點(diǎn)中每個(gè)元素的具體樣式胶背。
1、創(chuàng)建stylesheets(css規(guī)則樹(shù))
渲染引擎會(huì)把獲取到的CSS文本全部轉(zhuǎn)換為styleSheets結(jié)構(gòu)中的數(shù)據(jù)喘先,并且該結(jié)構(gòu)同時(shí)具備了查詢和修改功能,這會(huì)為后面的樣式操作提供基礎(chǔ)廷粒。
css樣式來(lái)源主要有三種:
- 通過(guò)link引用的外部CSS文件
-
<style>
標(biāo)記內(nèi)的 CSS -
元素的style屬性內(nèi)嵌的CSS
而styleSheets已經(jīng)把以上三種類(lèi)型的樣式包含進(jìn)去了窘拯。
2、轉(zhuǎn)換樣式表中的屬性值坝茎,使其標(biāo)準(zhǔn)化
CSS文本中有很多屬性值涤姊,如2em、blue嗤放、bold思喊,這些類(lèi)型數(shù)值不容易被渲染引擎理解,所以需要將所有值轉(zhuǎn)換為渲染引擎容易理解的次酌、標(biāo)準(zhǔn)化的計(jì)算值恨课。
3. 計(jì)算出DOM樹(shù)中每個(gè)節(jié)點(diǎn)的具體樣式
涉及到CSS的繼承規(guī)則和層疊規(guī)則舆乔。
繼承規(guī)則:CSS繼承就是每個(gè)DOM節(jié)點(diǎn)都包含有父節(jié)點(diǎn)的樣式。
層疊樣式:層疊是CSS的一個(gè)基本特征剂公,它是一個(gè)定義了如何合并來(lái)自多個(gè)源的屬性值的算法
總結(jié):樣式計(jì)算階段的目的是為了計(jì)算出DOM節(jié)點(diǎn)中每個(gè)元素的具體樣式希俩,在計(jì)算過(guò)程中需要遵守CSS的繼承和層疊兩個(gè)規(guī)則。這個(gè)階段最終輸出的內(nèi)容是每個(gè)DOM節(jié)點(diǎn)的樣式纲辽,并被保存在ComputedStyle的結(jié)構(gòu)內(nèi)颜武。
三、創(chuàng)建布局
1. 創(chuàng)建布局樹(shù)
你可能注意到了DOM樹(shù)還含有很多不可見(jiàn)的元素拖吼,比如head標(biāo)簽鳞上,還有使用了display:none屬性的元素。所以在顯示之前吊档,我們還要額外地構(gòu)建一棵只包含可見(jiàn)元素布局樹(shù)因块。
2. 布局計(jì)算
已有了一棵完整的布局樹(shù)。那么接下來(lái)籍铁,就要計(jì)算布局樹(shù)節(jié)點(diǎn)的坐標(biāo)位置涡上。
四、分層拒名,創(chuàng)建圖層樹(shù)
渲染引擎需要為特定的節(jié)點(diǎn)生成專(zhuān)用的圖層(如一些復(fù)雜的3D變換吩愧、頁(yè)面滾動(dòng),或者使用z-indexing做z軸排序等)增显,并生成一棵對(duì)應(yīng)的圖層樹(shù)(LayerTree)雁佳。
通常情況下,并不是布局樹(shù)的每個(gè)節(jié)點(diǎn)都包含一個(gè)圖層同云,如果一個(gè)節(jié)點(diǎn)沒(méi)有對(duì)應(yīng)的層糖权,那么這個(gè)節(jié)點(diǎn)就從屬于父節(jié)點(diǎn)的圖層。
五炸站、圖層繪制
圖層樹(shù)的構(gòu)建之后星澳,渲染引擎會(huì)對(duì)圖層樹(shù)中的每個(gè)圖層進(jìn)行繪制,輸出待繪制列表旱易,存放繪制操作命令禁偎。
六、柵格化(raster)操作阀坏,繪制
實(shí)際上繪制操作是由渲染引擎中的合成線程來(lái)完成的如暖。
當(dāng)圖層的繪制列表準(zhǔn)備好之后,
- 主線程會(huì)把該繪制列表提交(commit)給合成線程
- 合成線程會(huì)按照視口附近的圖塊來(lái)優(yōu)先生成位圖
- 實(shí)際生成位圖的操作是由柵格化(將圖塊轉(zhuǎn)換為位圖)來(lái)執(zhí)行的忌堂。
渲染進(jìn)程維護(hù)了一個(gè)柵格化的線程池盒至,所有的圖塊柵格化都是在線程池內(nèi)執(zhí)行的,運(yùn)行方式如下圖所示:
柵格化過(guò)程都會(huì)使用GPU來(lái)加速生成,使用GPU生成位圖的過(guò)程叫快速柵格化枷遂,或者GPU柵格化樱衷,生成的位圖被保存在GPU內(nèi)存中。GPU操作是運(yùn)行在GPU進(jìn)程中登淘,這就涉及到了跨進(jìn)程操作箫老。
七、合成和顯示
一旦所有圖塊都被光柵化黔州,合成線程就會(huì)生成一個(gè)繪制圖塊的命令——“DrawQuad”耍鬓,然后將該命令提交給瀏覽器進(jìn)程。
瀏覽器進(jìn)程里面的viz的組件接收合成線程發(fā)過(guò)來(lái)的DrawQuad命令流妻,將其頁(yè)面內(nèi)容繪制到內(nèi)存中牲蜀,最后再將內(nèi)存顯示在屏幕上。
八绅这、總結(jié):
- 渲染進(jìn)程將HTML內(nèi)容轉(zhuǎn)換為能夠讀懂的DOM樹(shù)結(jié)構(gòu)涣达。
- 渲染引擎將CSS樣式表轉(zhuǎn)化為瀏覽器可以理解的styleSheets,計(jì)算出DOM節(jié)點(diǎn)的樣式证薇。
- 創(chuàng)建布局樹(shù)度苔,并計(jì)算元素的布局信息。
- 對(duì)布局樹(shù)進(jìn)行分層浑度,并生成分層樹(shù)寇窑。
- 為每個(gè)圖層生成繪制列表,并將其提交到合成線程箩张。
- 合成線程將圖層分成圖塊甩骏,并在光柵化線程池中將圖塊轉(zhuǎn)換成位圖。
- 合成線程發(fā)送繪制圖塊命令DrawQuad給瀏覽器進(jìn)程先慷。
-
瀏覽器進(jìn)程根據(jù)DrawQuad消息生成頁(yè)面饮笛,并顯示到顯示器上。
另外论熙,重排和重繪:
1. 更新了元素的幾何屬性(重排)
如果通過(guò)js或者CSS修改元素的幾何位置屬性福青,如改變?cè)氐膶挾取⒏叨鹊雀岸牵瑫?huì)觸發(fā)重新布局素跺,解析之后的一系列子階段,這個(gè)過(guò)程就叫重排誉券。無(wú)疑,重排需要更新完整的渲染流水線刊愚,所以開(kāi)銷(xiāo)也是最大的
2. 更新元素的繪制屬性(重繪)
如果修改了元素的背景顏色踊跟,那么布局階段將不會(huì)被執(zhí)行,因?yàn)椴](méi)有引起幾何位置的變換,所以就直接進(jìn)入了繪制階段商玫,然后執(zhí)行之后的一系列子階段箕憾,這個(gè)過(guò)程就叫重繪。相較于重排操作拳昌,重繪省去了布局和分層階段袭异,所以執(zhí)行效率會(huì)比重排操作要高一些
3.直接合成階段
那如果更改一個(gè)既不要布局也不要繪制的屬性,渲染引擎將跳過(guò)布局和繪制炬藤,只執(zhí)行后續(xù)的合成操作御铃,我們把這個(gè)過(guò)程叫做合成。
使用了CSS的transform來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果沈矿,在非主線程上合成上真,并沒(méi)有占用主線程資源,避開(kāi)了布局和繪制兩個(gè)子階段羹膳,所以相對(duì)于重繪和重排睡互,合成能大大提升繪制效率。
在優(yōu)化Web性能的方法中陵像,減少重繪就珠、重排是一種很好的優(yōu)化方式:
- 觸發(fā)repaint reflow的操作盡量放在一起,比如改變dom高度和設(shè)置margin分開(kāi)寫(xiě)醒颖,可能會(huì)出發(fā)兩次重排
2.通過(guò)虛擬dom層計(jì)算出操作總得差異妻怎,一起提交給瀏覽器。之前還用過(guò)createdocumentfragment來(lái)匯總append的dom,來(lái)減少觸發(fā)重排重繪次數(shù)图贸。