摘要:而瀏覽器渲染與密切相關(guān),因此只有了解其中工作原理才能讓更好地工作。瀏覽器也稱為布局渲染方式瓦片渲染流暢動(dòng)畫(huà)總結(jié)參考文章瀏覽器用戶界面包括地址欄前進(jìn)后退按鈕書(shū)簽菜單等。瀏覽器引擎在用戶界面和渲染引擎之間傳送指令。渲染引擎負(fù)責(zé)顯示請(qǐng)求的內(nèi)容。
singsong: 文本是自己看了一些不錯(cuò)資料整理出來(lái)的,對(duì)該知識(shí)點(diǎn)感興趣的同學(xué)可以查看參考文章小節(jié)。
??最新內(nèi)容請(qǐng)以github上的為準(zhǔn)??
為什么要寫(xiě)這篇文章?主要為 CSS 優(yōu)化工作打一下基礎(chǔ)。要編寫(xiě)高性能的網(wǎng)站和應(yīng)用,除了確保編寫(xiě)的代碼盡可能高效地運(yùn)行外,還需要確保頁(yè)面性能,刷新頻率盡量到達(dá) 60FPS。這就需要了解瀏覽器是如何進(jìn)行渲染的。而瀏覽器渲染與 CSS 密切相關(guān),因此只有了解其中工作原理才能讓 CSS 更好地工作。
另外,接下來(lái)會(huì)出一篇優(yōu)化實(shí)戰(zhàn)文章,會(huì)涉及 JavaScript 和 CSS 一些優(yōu)化。其中關(guān)于 JavaScript 的優(yōu)化之前已進(jìn)行過(guò)介紹:常見(jiàn)的 JavaScript 內(nèi)存泄露。本文是對(duì) CSS 優(yōu)化進(jìn)行一個(gè)補(bǔ)充。
Contents瀏覽器
DOM tree
CSSOM tree
RenderObject tree(也稱為 Render tree)
Layout(布局)
RenderLayer tree
Rendering(渲染方式)
GrphicsLayer tree
Tiled Rendering(瓦片渲染)
High Performance Animations(流暢動(dòng)畫(huà))
總結(jié)
參考文章
瀏覽器用戶界面(User Interface):包括地址欄、前進(jìn)/后退按鈕、書(shū)簽菜單等。除了瀏覽器主窗口顯示的您請(qǐng)求的頁(yè)面外,其他顯示的各個(gè)部分都屬于用戶界面。
瀏覽器引擎(Browser engine):在用戶界面(User Interface)和渲染引擎(Rendering engine)之間傳送指令。
渲染引擎(Rendering engine):負(fù)責(zé)顯示請(qǐng)求的內(nèi)容。如果請(qǐng)求的內(nèi)容是 HTML,它就負(fù)責(zé)解析 HTML 和 CSS 內(nèi)容,并將解析后的內(nèi)容顯示在屏幕上。
網(wǎng)絡(luò)(Networking):用于網(wǎng)絡(luò)調(diào)用,比如 HTTP 請(qǐng)求。其接口與平臺(tái)無(wú)關(guān),并為所有平臺(tái)提供底層實(shí)現(xiàn)。
JavaScript 解釋器(JavaScript Interperter):用于解析和執(zhí)行 JavaScript 代碼。
用戶界面后端(UI Backend):用于繪制基本的窗口小部件,比如組合框和窗口。其公開(kāi)了與平臺(tái)無(wú)關(guān)的通用接口,而在底層使用操作系統(tǒng)的用戶界面方法。
數(shù)據(jù)存儲(chǔ)(Data storage):這是持久層。瀏覽器需要在硬盤(pán)上保存各種數(shù)據(jù),例如 Cookies。瀏覽器還支持諸如 localStorage,IndexedDB,WebSQL 和 FileSystem 之類的存儲(chǔ)機(jī)制。
本文主要介紹瀏覽器的渲染,即渲染引擎(Rendering engine)負(fù)責(zé)的工作: 將請(qǐng)求的 HTML 和 CSS 內(nèi)容解析并渲染在屏幕上。
DOM treeDOM:Document Object Model,文檔對(duì)象模型。它可以以一種獨(dú)立于平臺(tái)和語(yǔ)言的方式,訪問(wèn)和修改一個(gè)文檔的內(nèi)容和結(jié)構(gòu)。它定義了一組與平臺(tái),語(yǔ)言無(wú)關(guān)的接口,該接口允許編程語(yǔ)言動(dòng)態(tài)地訪問(wèn)和修改結(jié)構(gòu)化文檔?;?DOM 表示的文檔被描述成一個(gè)樹(shù)形結(jié)構(gòu),使用 DOM 的接口可以對(duì) DOM 樹(shù)進(jìn)行操作。
這里以一個(gè)實(shí)例展開(kāi)講解,如下 HTML 結(jié)構(gòu)包含一些文本和一張圖片:
Critical Path Hello web performance students!
瀏覽器是如何處理這個(gè) HTML 頁(yè)面:
轉(zhuǎn)換(Conversion):瀏覽器從磁盤(pán)或網(wǎng)絡(luò)讀取 HTML 的字節(jié)碼,并根據(jù)文件的指定編碼(例如 UTF-8)將其轉(zhuǎn)換成對(duì)應(yīng)的字符。
令牌化(Tokenizing):瀏覽器將字符串轉(zhuǎn)換成W3C HTML5 標(biāo)準(zhǔn)規(guī)定的各種 token,例如、,以及其他尖括號(hào)內(nèi)的字符串。每個(gè) token 都具有一定特殊含義和規(guī)則。
詞法分析(Lexing):將 token 轉(zhuǎn)換成定義其屬性和規(guī)則的“對(duì)象”。
DOM tree:HTML 標(biāo)簽定義了不同標(biāo)簽之間的關(guān)系(某些標(biāo)簽包含在其他標(biāo)簽中),所創(chuàng)建的對(duì)象鏈接在樹(shù)狀數(shù)據(jù)結(jié)構(gòu)中,該數(shù)據(jù)結(jié)構(gòu)還捕獲原始標(biāo)簽中定義的父——子關(guān)系:HTML 是 body 的父對(duì)象,body 是段落的父對(duì)象,依此類推。
整個(gè)過(guò)程的最終輸出是 HTML 頁(yè)面的 DOM tree,后續(xù)瀏覽器對(duì)頁(yè)面進(jìn)一步的所有處理都會(huì)用到它。瀏覽器每次處理 HTML 標(biāo)簽時(shí),都會(huì)完成以上所有步驟:將字節(jié)轉(zhuǎn)換成字符,確定 token,將 token 轉(zhuǎn)換成節(jié)點(diǎn),然后構(gòu)建 DOM tree。
CSSOM treeCSSOM:CSS Object Model,CSS 對(duì)象模型。CSSOM 定義了 JavaScript 訪問(wèn)樣式的能力和方式。它是在 DOM 中的一些接口中,加入獲取和操作 CSS 屬性或接口的 JavaScript 接口,因而 JavaScript 可以動(dòng)態(tài)操作 CSS 樣式。DOM 提供了接口讓 JavaScript 修改 HTML 文檔,CSSOM 提供了接口讓 JavaScript 獲得和修改 CSS 代碼設(shè)置的樣式信息。
在瀏覽器構(gòu)建 DOM 遇到 link 標(biāo)簽時(shí),該標(biāo)簽引用一個(gè)外部 CSS 樣式表:style.css。由于預(yù)見(jiàn)到需要利用該資源來(lái)渲染頁(yè)面,它會(huì)立即發(fā)出對(duì)該資源的請(qǐng)求,并返回以下內(nèi)容:
body { font-size: 16px } p { font-weight: bold } span { color: red } p span { display: none } img { float: right }
與處理 HTML 時(shí)類似,需要將收到的 CSS 規(guī)則轉(zhuǎn)換成某種瀏覽器能夠理解和處理的內(nèi)部表示。因此會(huì)重復(fù) HTML 過(guò)程,不過(guò)是對(duì) CSS 而不是 HTML:
將 CSS 字節(jié)轉(zhuǎn)換成字符,接著轉(zhuǎn)換成 token 和節(jié)點(diǎn),最后將它們鏈接到 CSSOM tree 結(jié)構(gòu)中:
CSSOM tree 可以用于確定節(jié)點(diǎn)對(duì)象的計(jì)算樣式。如 span 標(biāo)記包含了color:red樣式和繼承于 body 標(biāo)記的font-size:16px樣式;
RenderObject tree(也稱為 Render tree)在 DOM tree 中,存在不可見(jiàn)與可見(jiàn)節(jié)點(diǎn)之分。顧名思義,不可見(jiàn)節(jié)點(diǎn)是不需要繪制最終頁(yè)面中的節(jié)點(diǎn),如meta、head、script等,以及通過(guò) CSS 樣式display:none隱藏的節(jié)點(diǎn)。相反可見(jiàn)節(jié)點(diǎn)是用戶可見(jiàn)的,如body、div、span、canvas、img等。對(duì)于這些可見(jiàn)節(jié)點(diǎn),瀏覽器需要將它們的內(nèi)容繪制到最終的頁(yè)面中,所以瀏覽器會(huì)為它們建立對(duì)應(yīng)的 RenderObject 對(duì)象。一個(gè) RenderObject 對(duì)象保存了為繪制 DOM 節(jié)點(diǎn)的各種信息。這些 RenderObject 對(duì)象與 DOM 對(duì)象類似,也構(gòu)成一棵樹(shù),稱為RenderObject tree。RenderObject tree 是基于 DOM tree 建立起來(lái)的一棵新樹(shù),是為了布局計(jì)算和渲染等機(jī)制而構(gòu)建的一種新的內(nèi)部表示。RenderObject tree 節(jié)點(diǎn)與 DOM tree 節(jié)點(diǎn)不是一一對(duì)應(yīng)關(guān)系。因?yàn)閯?chuàng)建一個(gè) RenderObject 對(duì)象需要滿足如下規(guī)則:
DOM tree 的 document 節(jié)點(diǎn)
DOM tree 中的可見(jiàn)節(jié)點(diǎn),如html、body、div等。而瀏覽器不會(huì)為不可見(jiàn)節(jié)點(diǎn)創(chuàng)建 RenderObject 節(jié)點(diǎn)。
某些情況下瀏覽器需要?jiǎng)?chuàng)建匿名的 RenderObject 節(jié)點(diǎn),該節(jié)點(diǎn)不對(duì)應(yīng) DOM 樹(shù)中的任何節(jié)點(diǎn)。
RenderObject 對(duì)象構(gòu)成了 RenderObject tree,每個(gè) RenderObject 對(duì)象保存了為繪制 DOM 節(jié)點(diǎn)的計(jì)算樣式。RenderObject tree 也可以理解成由 CSSOM tree 和 DOM tree 合并成:
Layout(布局)當(dāng)瀏覽器創(chuàng)建 RenderObject 對(duì)象之后,每個(gè)對(duì)象并不知道自己在設(shè)備視口內(nèi)的位置、大小等信息。瀏覽器根據(jù)盒模型(Box-model)來(lái)計(jì)算它們的位置、大小等信息的過(guò)程稱為布局計(jì)算(重排)。布局計(jì)算是一個(gè)遞歸的過(guò)程,這是因?yàn)橐粋€(gè)節(jié)點(diǎn)的大小通常需要先計(jì)算它的孩子節(jié)點(diǎn)的位置、大小等信息。為了計(jì)算節(jié)點(diǎn)在頁(yè)面中的確切大小和位置,瀏覽器會(huì)從 RenderObject tree 的根節(jié)點(diǎn)開(kāi)始進(jìn)行遍歷。
實(shí)例:
Critial Path: Hello world! Hello world!
頁(yè)面包含了兩個(gè)嵌套 div:父 div 將其的顯示尺寸設(shè)置為 viewport 寬度的 50%,子 div 將其寬度設(shè)置為其父項(xiàng)的 50%,即 viewport 寬度的 25%。
RenderLayer tree瀏覽器渲染引擎并不是直接使用 RenderObject tree 進(jìn)行繪制,為了方便處理 Positioning(定位),Clipping(裁剪),Overflow-scroll(頁(yè)內(nèi)滾動(dòng)),CSS Transform/Opacity/Animation/Filter,Mask or Reflection,Z-indexing(Z 排序)等,瀏覽器需要會(huì)為一些特定的 RenderObject 生成對(duì)應(yīng)的 RenderLayer,并生成一棵對(duì)應(yīng)的 RenderLayer tree。而這些特定的 RenderObject 跟對(duì)應(yīng)的 RenderLayer 就是直屬的關(guān)系,如果它們的子節(jié)點(diǎn)如果沒(méi)有對(duì)應(yīng)的 RenderLayer,就從屬于父節(jié)點(diǎn)的 RenderLayer。最終,每一個(gè) RenderObject 都會(huì)直接或者間接地從屬于一個(gè) RenderLayer。因此 RenderObject 節(jié)點(diǎn)與 RenderLayer 節(jié)點(diǎn)不是一一對(duì)應(yīng)關(guān)系,而是一對(duì)多的關(guān)系。那需要滿足什么條件,渲染引擎才為 RenderObject 建立對(duì)應(yīng)的 RenderLayer:
It"s the root object for the page
It has explicit CSS position properties (relative, absolute or a transform)
It is transparent
Has overflow, an alpha mask or reflection
Has a CSS filter
Corresponds to element that has a 3D (WebGL) context or an accelerated 2D context
Corresponds to a element
翻譯:
DOM tree 的 Document 節(jié)點(diǎn)對(duì)應(yīng)的 RenderObject 節(jié)點(diǎn)和 HTML 節(jié)點(diǎn)對(duì)應(yīng)的 RenderObject 節(jié)點(diǎn)
顯式指定 CSS position 屬性的 RenderObject 節(jié)點(diǎn)
有透明度的 RenderObject 節(jié)點(diǎn)
有 overflow,alpha 和 reflection 的樣式 RenderObject 節(jié)點(diǎn)
有 filter 樣式的 RenderObject 節(jié)點(diǎn)
使用 Canvas 2D 和 3D(WebGL)技術(shù)的 RenderObject 節(jié)點(diǎn)
video 元素對(duì)應(yīng)的 RenderObject 節(jié)點(diǎn)
每個(gè) RenderLayer 對(duì)象可以想象成圖像中一個(gè)圖層,各個(gè)圖層疊加構(gòu)成了一個(gè)圖像。瀏覽器會(huì)遍歷 RenderLayer tree,再遍歷從屬這個(gè) RenderLayer 的 RenderObject,RenderObject 對(duì)象存儲(chǔ)有繪制信息,并進(jìn)行繪制。RenderLayer 和 RenderObject 共同決定了最終呈現(xiàn)的網(wǎng)頁(yè)內(nèi)容,RenderLayer tree 決定了網(wǎng)頁(yè)的繪制的層次順序,而從屬于 RenderLayer 的 RenderObject 決定了該 RenderLayer 的內(nèi)容。
Rendering(渲染方式)在完成構(gòu)建 RenderLayer tree 之后,瀏覽器會(huì)使用圖形庫(kù)將其構(gòu)建的渲染模型繪制出來(lái),該過(guò)程分為兩個(gè)階段:
繪制:將從屬每個(gè) RenderLayer 圖層上的 RenderObject 繪制在其 RenderLayer 上。即繪制(Paint)或者光柵化(Rasterization),將一些繪圖指令轉(zhuǎn)換成真正的像素顏色值。
軟件繪圖:CPU 來(lái)完成繪圖操作
硬件加速繪圖:GPU 來(lái)完成繪圖操作
合成(compositing):將各個(gè) RenderLayer 圖層合并成到一個(gè)位圖(Bitmap)中。同時(shí)還可能包括位移(Translation),縮放(Scale),旋轉(zhuǎn)(Rotation),Alpha 合成等操作。
渲染引擎的渲染,目前有三種網(wǎng)頁(yè)的渲染方式:
硬件加速合成(Accelerated Compositing):使用 GPU 來(lái)完成合成工作。
合成化渲染:使用合成(compositing)技術(shù)的渲染稱。
軟件渲染方式:使用 CPU 來(lái)繪制每個(gè) RenderLayer 圖層的內(nèi)容(RenderObject)到一個(gè)位圖,即一塊 CPU 使用的內(nèi)存空間。繪制每一層的時(shí)候都會(huì)使用該位圖,區(qū)別在于繪制的位置可能不一樣,繪制順序按照從后到前。因此軟件渲染機(jī)制是沒(méi)有合成階段的。
硬件加速渲染的合成化渲染方式:使用 GPU 來(lái)繪制所有合成層,并使用 GPU 硬件來(lái)加速合成。
軟件繪圖的合成化渲染方式: 某些合成層使用 CPU 來(lái)繪圖,另外一些使用 GPU 來(lái)繪制。對(duì)于使用 CPU 來(lái)繪制的圖層,該層的繪制結(jié)果會(huì)先保存在 CPU 內(nèi)存中,之后會(huì)被傳輸?shù)?GPU 內(nèi)存中,然后再使用 GPU 來(lái)完成合成工作。
第二種和第三種渲染方式,都是使用了合成化渲染技術(shù),合成工作也都是由 GPU 來(lái)做。對(duì)于常見(jiàn)的 2D 繪圖操作,使用 GPU 來(lái)繪圖不一定比使用 CPU 繪圖在性能上有優(yōu)勢(shì),例如繪制文字、點(diǎn)、線等。原因是 CPU 的使用緩沖機(jī)制有效減少了重復(fù)繪制的開(kāi)銷而且不需要考慮與 GPU 并行。另外,GPU 的內(nèi)存資源相對(duì) CPU 的內(nèi)存資源來(lái)說(shuō)比較緊張,而且網(wǎng)頁(yè)的分層使得 GPU 的內(nèi)存使用相對(duì)比較多。鑒于此,就目前的情況來(lái)看,三者都存在是有其合理性的,下面分析一下它們的特點(diǎn):
軟件渲染是目前很常見(jiàn)的技術(shù),也是瀏覽器最早使用的渲染方式。這一技術(shù)比較節(jié)省內(nèi)存,特別是寶貴的 GPU 內(nèi)存,但是軟件渲染只能處理 2D 方面的操作。簡(jiǎn)單的網(wǎng)頁(yè)沒(méi)有復(fù)雜繪圖或者多媒體方面的需求,軟件渲染方式就比較合適來(lái)渲染該類型的網(wǎng)頁(yè)。問(wèn)題是,一旦遇上了 HTML5 的很多新技術(shù),軟件渲染顯得無(wú)能為力,一是因?yàn)槟芰Σ蛔?;二是因?yàn)樾阅懿缓茫缫曨l、Canvas 2D 等。所以,軟件渲染技術(shù)被用的越來(lái)越少,特別是在移動(dòng)領(lǐng)域。軟件渲染同硬件加速渲染另外一個(gè)很不同的地方就是對(duì)更新區(qū)域的處理。當(dāng)網(wǎng)頁(yè)中有一個(gè)更新小型區(qū)域的請(qǐng)求(如動(dòng)畫(huà))時(shí),軟件渲染可能只需要計(jì)算一個(gè)極小的區(qū)域,而硬件渲染可能需要重新繪制其中的一層或者多層,然后再合成這些層。硬件渲染的代價(jià)可能會(huì)大得多。
對(duì)于硬件加速的合成化渲染方式來(lái)說(shuō),每個(gè)層的繪制和所有層的合成均使用 GPU 硬件來(lái)完成,這對(duì)需要使用 3D 繪圖的操作來(lái)說(shuō)特別合適。這種方式下,在 RenderLayer 樹(shù)之后,瀏覽器還需要建立更多的內(nèi)部表示,目的是支持硬件加速機(jī)制,這顯然會(huì)消耗更多的內(nèi)存資源。但是,一方面,硬件加速機(jī)制能夠支持現(xiàn)在所有的 HTML5 定義的 2D 或者 3D 繪圖標(biāo)準(zhǔn);另一方面,關(guān)于更新區(qū)域的討論,如果需要更新某個(gè)層的一個(gè)區(qū)域,因?yàn)檐浖秩緵](méi)有為每一層提供后端存儲(chǔ),因而它需要將和這個(gè)區(qū)域有重疊部分的所有層次的相關(guān)區(qū)域一次從后往前重新繪制一遍,而硬件加速渲染只需要重新繪制更新發(fā)生的層次,因而在某些情況下,軟件渲染的代價(jià)又變得更大。當(dāng)然,這取決于網(wǎng)頁(yè)的結(jié)構(gòu)和渲染策略。
軟件繪圖的合成化渲染方式結(jié)合了前面兩種方式的優(yōu)點(diǎn),這時(shí)因?yàn)楹芏嗑W(wǎng)頁(yè)可能既包含基本的 HTML 元素,也包含一些 HTML5 新功能,使用 CPU 繪圖方式來(lái)繪制某些層,使用 GPU 來(lái)繪制其他一些層。原因當(dāng)然是前面所述的基于性能和內(nèi)存方面綜合考慮的結(jié)果。
瀏覽器還可以使用多線程的渲染架構(gòu),將網(wǎng)頁(yè)內(nèi)容繪制到后端存儲(chǔ)的操作放到另外一個(gè)獨(dú)立的線程(繪制線程),而原來(lái)線程轉(zhuǎn)為合成線程,繪制線程跟合成線程之間可以使用同步,部分同步,完全異步等作業(yè)模式,讓瀏覽器可以在性能與效果之間根據(jù)需要進(jìn)行選擇。GrphicsLayer tree
對(duì)于軟件渲染而言,到 RenderLayer tree 就結(jié)束了,后面不會(huì)建立其它額外的樹(shù)來(lái)對(duì)應(yīng)于 RenderLayer tree。但是,對(duì)于硬件渲染來(lái)說(shuō),在 RenderLayer tree 之后,瀏覽器渲染引擎為硬件渲染提供了更多的內(nèi)部結(jié)構(gòu)來(lái)支持這個(gè)機(jī)制。
在硬件加速渲染的合成化渲染和軟件繪圖的合成化渲染架構(gòu)下,一個(gè) RenderLayer 對(duì)象如果需要后端存儲(chǔ),它會(huì)創(chuàng)建一個(gè) RenderLayerBacking 對(duì)象,該對(duì)象負(fù)責(zé) Renderlayer 對(duì)象所需要的各種存儲(chǔ)。理想情況下,每個(gè) RenderLayer 都可以創(chuàng)建自己的后端存儲(chǔ),事實(shí)上不是所有 RenderLayer 都有自己的 RenderLayerBacking 對(duì)象。如果一個(gè) RenderLayer 對(duì)象被像樣的創(chuàng)建后端存儲(chǔ),那么將該 RenderLayer 稱為合成層(Compositing Layer)。
哪些 RenderLayer 對(duì)象可以是合成層?如果一個(gè) RenderLayer 對(duì)象具有以下的特征之一,那么它就是合成層:
Layer has 3D or perspective transform CSS properties
Layer is used by < video> element using accelerated video decoding
Layer is used by a < canvas> element with a 3D context or accelerated 2D context
Layer is used for a composited plugin
Layer uses a CSS animation for its opacity or uses an animated webkit transform
Layer uses accelerated CSS filters
Layer with a composited descendant has information that needs to be in the composited layer tree, such as a clip or reflection
Layer has a sibling with a lower z-index which has a compositing layer (in other words the layer is rendered on top of a composited layer)
翻譯:
RenderLayer 具有 3D 或透視轉(zhuǎn)換的 CSS 屬性
RenderLayer 包含使用硬件加速的視頻解碼技術(shù)的元素
RenderLayer 包含使用硬件加速的 2D 或 WebGL-3D 技術(shù)的元素
RenderLayer 使用了合成插件。
RenderLayer 使用了opacity或transform動(dòng)畫(huà)
RenderLayer 使用了硬件加速的 CSS Filters 技術(shù)
RenderLayer 后代中包含了一個(gè)合成層(如有 clip 或 reflection 屬性)
RenderLayer 有一個(gè) z-index 比自己小的合成層(即在一個(gè)合成層之上)
每個(gè)合成層都有一個(gè) RenderLayerBacking,RenderLayerBacking 負(fù)責(zé)管理 RenderLayer 所需要的所有后端存儲(chǔ),因?yàn)楹蠖舜鎯?chǔ)可能需要多個(gè)存儲(chǔ)空間。在瀏覽器(WebKit)中,存儲(chǔ)空間使用類 GraphicsLayer 來(lái)表示。瀏覽器會(huì)為這些 RenderLayer 創(chuàng)建對(duì)應(yīng)的 GraphicsLayer,不同的瀏覽器需要提供自己的 GrphicsLayer 實(shí)現(xiàn)用于管理存儲(chǔ)空間的分配,釋放,更新等等。擁有 GrphicsLayer 的 RenderLayer 會(huì)被繪制到自己的后端存儲(chǔ),而沒(méi)有 GrphicsLayer 的 RenderLayer 它們會(huì)向上追溯有 GrphicsLayer 的父/祖先 RenderLayer,直到 Root RenderLayer 為止,然后繪制在有 GrphicsLayer 的父/祖先 RenderLayer 的存儲(chǔ)空間,而 Root RenderLayer 總是會(huì)創(chuàng)建一個(gè) GrphicsLayer 并擁有自己獨(dú)立的存儲(chǔ)空間。在將每個(gè)合成圖層包含的 RenderLayer 內(nèi)容繪制在合成層的后端存儲(chǔ)中,這里繪制可以是軟件繪制或硬件繪制。接著由合成器(Compositor)將多個(gè)合成層合成起來(lái),形成最終用戶可見(jiàn)的網(wǎng)頁(yè),實(shí)際上就是一張圖片。
GraphicsLayer 又構(gòu)成了一棵與 RenderLayer 并行的樹(shù),而 RenderLayer 與 GraphicsLayer 的關(guān)系有些類似于 RenderObject 與 RenderLayer 之間的關(guān)系。如下是 DOM tree、RenderObject tree、RenderLayer tree、GraphicsLayer tree關(guān)系圖:
這樣可以合并一些 RenderLayer 層,從而減少內(nèi)存的消耗。其次,合并之后,減少了合并帶來(lái)的重繪性能和處理上的困難。在硬件加速渲染的合成化渲染和軟件繪圖的合成化渲染架構(gòu)下,RenderLayer 的內(nèi)容變化,只需要更新所屬的 GraphicsLayer 的緩存即可,而緩存的更新,也只需要繪制直接或者間接屬于這個(gè) GraphicsLayer 的 RenderLayer,而不是所有的 RenderLayer。特別是一些特定的 CSS 樣式屬性的變化,實(shí)際上并不引起內(nèi)容的變化,只需要改變一些 GraphicsLayer 的混合參數(shù),然后重新混合即可,而混合相對(duì)繪制而言是很快的,這些特定的 CSS 樣式屬性我們一般稱之為是被加速的,不同的瀏覽器支持的狀況不太一樣,但基本上 CSS Transform & Opacity 在所有支持混合加速的瀏覽器上都是被加速的。被加速的 CSS 樣式屬性的動(dòng)畫(huà),就比較容易達(dá)到 60 幀/每秒的流暢效果了。
不過(guò)并不是擁有獨(dú)立緩存的 RenderLayer 越多越好,太多擁有獨(dú)立緩存的 RenderLayer 會(huì)帶來(lái)一些嚴(yán)重的副作用:
它大大增加了內(nèi)存的開(kāi)銷,這點(diǎn)在移動(dòng)設(shè)備上的影響更大,甚至導(dǎo)致瀏覽器在一些內(nèi)存較少的移動(dòng)設(shè)備上無(wú)法很好地支持圖層合成加速;
它加大了合成的時(shí)間開(kāi)銷,導(dǎo)致合成性能的下降,而合成性能跟網(wǎng)頁(yè)滾動(dòng)/縮放操作的流暢度又息息相關(guān),最終導(dǎo)致網(wǎng)頁(yè)滾動(dòng)/縮放的流暢度下降,讓用戶覺(jué)得操作不夠流暢。
Tiled Rendering(瓦片渲染)通常一個(gè)合成層的后端存儲(chǔ)被分割成多個(gè)大小相同的瓦片狀的小存儲(chǔ)空間,每個(gè)瓦片可以理解為 OpenGL 中的一個(gè)紋理,合成層的結(jié)果被分開(kāi)存儲(chǔ)在這些瓦片中。為什么使用瓦片化的后端存儲(chǔ)?
DOM 樹(shù)種的 html 元素所在的層可能會(huì)比較大,因?yàn)榫W(wǎng)頁(yè)的高度很大,如果只是使用一個(gè)后端存儲(chǔ)的話,那么需要一個(gè)很大的紋理對(duì)象,但是實(shí)際的 GPU 硬件可能只支持非常有限的紋理大小。
在一個(gè)比較大的合成層中,可能只是其中一部分發(fā)生變化,根據(jù)之前的介紹,需要重新繪制整個(gè)層,這樣必然產(chǎn)生額外的開(kāi)銷,使用瓦片話的后端存儲(chǔ),就只需要重繪一些存在更新的瓦片。
當(dāng)層發(fā)生滾動(dòng)的時(shí)候,一些瓦片可能不再需要,然后渲染引擎需要一些新的瓦片來(lái)繪制新的區(qū)域,這些大小相同的后端存儲(chǔ)很容易重復(fù)利用。
High Performance Animations(流暢動(dòng)畫(huà))網(wǎng)頁(yè)加載后,繪制新的每一幀,一般都需要經(jīng)過(guò)計(jì)算布局(layout)、繪圖(paint)、合成(composite)三階段。因此要想提高頁(yè)面性能(或 FPS),需要減少每一幀的時(shí)間。而在這三個(gè)階段中,layout 和 paint 比較耗時(shí)間,而合成需要的時(shí)間相對(duì)較少一些。
layout如果修改 DOM 元素的 layout 樣式(如 width, heihgt 等),瀏覽器會(huì)計(jì)算頁(yè)面需要 relayout 的元素,然后觸發(fā)一個(gè) relayout。被 relayout 的元素,接著會(huì)執(zhí)行繪制,最后進(jìn)行渲染合并生成頁(yè)面。
如果修改 DOM 元素的 paint 樣式(如 color, background 等),瀏覽器會(huì)跳過(guò)布局,直接執(zhí)行繪制,再進(jìn)行合成。
如果修改 DOM 元素的 composite 樣式(如 transform, opacity 等)。瀏覽器會(huì)跳過(guò)布局和繪制,直接執(zhí)行合成。該過(guò)程是開(kāi)銷最小的,也是優(yōu)化著手點(diǎn)。
如果想知道修改任何指定 CSS 樣式會(huì)觸發(fā) layout、paint、composite 中的哪一個(gè),請(qǐng)查看CSS 觸發(fā)器。
優(yōu)化可以通過(guò)什么途徑進(jìn)行優(yōu)化,減少每一幀的時(shí)間(避免過(guò)多 layout 或 paint):
使用適合的網(wǎng)頁(yè)分層技術(shù)減少 layout 和 paint。一旦有請(qǐng)求更新,如果沒(méi)有分層,渲染引擎可能需要重新繪制所有區(qū)域,因?yàn)橛?jì)算更新部分對(duì) GPU 來(lái)說(shuō)可能消耗更多的時(shí)間。而網(wǎng)頁(yè)分層之后,部分區(qū)域的更新可能只在網(wǎng)頁(yè)的一層或幾層,而不需要將整個(gè)網(wǎng)頁(yè)重新繪制。通過(guò)重新繪制網(wǎng)頁(yè)的一層或幾層,并將它們和其他之前繪制完的層合并起來(lái),既能使用 GPU 的能力,又能夠減少重繪的開(kāi)銷。
使用合成屬性樣式(opcity、tansform)來(lái)完成 tansition 或 animation。當(dāng)合成器合成時(shí)候,每個(gè)合成層都可以設(shè)置變形屬性:位移(Translate)、縮放(Scale)、旋轉(zhuǎn)(Rotation)、opacity,這些屬性僅僅改變合成層的變換參數(shù),而不需要 layout 和 paint 操作,極大地減少每一幀的渲染時(shí)間。
即使用 GPU 硬件加速,為某些 RenderLayer 創(chuàng)建對(duì)應(yīng) GraphicsLayer。通過(guò)為每一個(gè)合成層設(shè)置transform屬性來(lái)完成 transition 或 animation,有效地避免 relayout 和 repaint 的開(kāi)銷。
總結(jié)本文重點(diǎn)介紹了瀏覽器渲染引擎的渲染過(guò)程,涉及了 DOM tree、CSSOM tree、RenderObject tree、RenderLayer tree、GraphicsLayer tree。并對(duì)各種渲染模式進(jìn)行了簡(jiǎn)單介紹,其中引入了硬件加速機(jī)制,還給出一些優(yōu)化建議。了解這些知識(shí)點(diǎn)對(duì)我們開(kāi)發(fā)高性能的 web 應(yīng)用會(huì)有很大的幫助。
參考文章:GPU Accelerated Compositing in Chrome
瀏覽器的工作原理:新式網(wǎng)絡(luò)瀏覽器幕后揭秘
構(gòu)建對(duì)象模型
How Rendering Work (in WebKit and Blink)
WebKit 技術(shù)內(nèi)幕
渲染性能
High Performance Animations
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/113232.html
摘要:作者兩年經(jīng)驗(yàn)第一家任職的是個(gè)小公司第二家算是二線互聯(lián)網(wǎng)公司各待了一年吧能有機(jī)會(huì)去阿里面試很驚喜先來(lái)和大家分享一下面試經(jīng)歷電話面試初探因?yàn)檫€在職的緣故電話面試從晚上點(diǎn)鐘開(kāi)始持續(xù)了半個(gè)小時(shí)左右一開(kāi)始的時(shí)候特比緊張甚至聲音略有些顫抖簡(jiǎn)單自我介紹做 作者兩年經(jīng)驗(yàn), 第一家任職的是個(gè)小公司, 第二家算是二線互聯(lián)網(wǎng)公司, 各待了一年吧... 能有機(jī)會(huì)去阿里面試很驚喜! 先來(lái)和大家分享一下面試經(jīng)歷....
摘要:這個(gè)階段只有一個(gè)方法,該方法在整個(gè)生命周期內(nèi)調(diào)用且僅調(diào)用一次。在這里進(jìn)行一些相關(guān)的銷毀操作,比如撤銷定時(shí)器,事件監(jiān)聽(tīng)等等。 詳解 React 生命周期 整個(gè) React 生命周期有3個(gè)階段:創(chuàng)建、更新、卸載,每個(gè)階段有對(duì)應(yīng)的工作和方法,我們可以看下面這個(gè)經(jīng)典的圖研究一下: showImg(https://segmentfault.com/img/remote/1460000016330...
摘要:一個(gè)網(wǎng)頁(yè)從我們輸入網(wǎng)址到打開(kāi)經(jīng)歷了以下步驟。如果沒(méi)有或記錄已經(jīng)過(guò)期,則向域名解析服務(wù)器發(fā)送解析請(qǐng)求。服務(wù)器收到請(qǐng)求,產(chǎn)生響應(yīng),并將網(wǎng)頁(yè)發(fā)送給負(fù)載均衡服務(wù)器。負(fù)載均衡服務(wù)器將網(wǎng)頁(yè)傳遞給鏈處理,之后發(fā)回給我們的瀏覽器。 一個(gè)網(wǎng)頁(yè)從我們輸入網(wǎng)址到打開(kāi)經(jīng)歷了以下步驟。 showImg(https://segmentfault.com/img/bVbpfj2?w=232&h=555); DNS...
摘要:而瀏覽器渲染與密切相關(guān),因此只有了解其中工作原理才能讓更好地工作。瀏覽器也稱為布局渲染方式瓦片渲染流暢動(dòng)畫(huà)總結(jié)參考文章瀏覽器用戶界面包括地址欄前進(jìn)后退按鈕書(shū)簽菜單等。瀏覽器引擎在用戶界面和渲染引擎之間傳送指令。渲染引擎負(fù)責(zé)顯示請(qǐng)求的內(nèi)容。 singsong: 文本是自己看了一些不錯(cuò)資料整理出來(lái)的,對(duì)該知識(shí)點(diǎn)感興趣的同學(xué)可以查看參考文章小節(jié)。 ??最新內(nèi)容請(qǐng)以github上的為準(zhǔn)?? 為...
閱讀 3577·2021-08-02 13:41
閱讀 2448·2019-08-30 15:56
閱讀 1526·2019-08-30 11:17
閱讀 1186·2019-08-29 15:18
閱讀 590·2019-08-29 11:10
閱讀 2681·2019-08-26 13:52
閱讀 520·2019-08-26 13:22
閱讀 2962·2019-08-23 15:41