基於Webkit的瀏覽器關鍵渲染路徑介紹
關鍵渲染路徑概念
瀏覽器是如何將HTML、JS、CSS、image等資源渲染成視覺化的頁面的呢?本文簡單介紹一下渲染過程中涉及到的關鍵步驟。
該過程分為四步:模型物件的構建、渲染樹構建、佈局、繪製。
1.模型物件的構建
瀏覽器獲取到HTML、CSS檔案後,需要對其進行解析,抽象成DOM和CSSOM物件,然後提供相應的JS API,方便開發者進行互動邏輯開發。
HTML檔案位元組轉變成DOM的過程如下圖所示:
主要經歷字元編碼—》令牌提取標籤—》詞法分析轉變成DOM物件—》依照標籤的巢狀關係構建成DOM樹;
CSS檔案位元組轉變成CSSOM的過程與HTML轉DOM類似,區別就是按照規則通用性建立樹形關係。
2.渲染樹的構建
所謂渲染樹,就是將DOM樹和CSSOM樹合併,得到每個可見元素的內容和顯示樣式。
Tips:
(1)渲染樹並非顯示所有元素,而只是佔據空間元素,如display: none的元素不在渲染樹中,而visibility: hidden的在渲染樹中;
(2)渲染樹包含的內容只是元素的內容及其樣式資訊,在不同視口(viewport,也就是瀏覽器的螢幕畫布)下實際展示肯能會有差別;
(3)渲染樹構建後,Webkit還會繼續構建渲染層(RenderLayer),這是為了簡化渲染邏輯,同時方便開發者檢視網頁層次。
3.佈局
經過前兩步的操作,我們知道了元素的內容和樣式資訊,但是實際在不同顯示器中的大小和位置如何確定呢,這就需要進行佈局操作了,有的地方稱為"自動重排"(reflow)。Webkit依據框模型來計算元素的位置和大小,佈局輸出的是一個"盒模型"物件,該物件包含了每個元素在視口內的確切位置和尺寸。
4.繪製
在佈局結束後,接下來就是繪製,實現柵格化。繪製一般涉及到Paint和Composite Layers。
Paint一般通過影象上下文來控制,分為2D和3D繪製上下文。
前文提到了RenderLayer的概念,繪製過程中,每個RenderLayer是輸出影象中的一層,各個層根據深度資訊組合成一張影象,這個組合的過程稱為Composite Layers。
關鍵渲染路徑開發相關
介紹完了關鍵渲染路徑的概念,接下來結合chrome dev-tool來看一下實際的情況,chrome的版本是60.0。
1.程式碼
<html> <head> <title>Janky Animation</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="index.css"/> <link rel="stylesheet" type="text/css" href="https://ss1.bdstatic.com/ 5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/soutu/css/soutu.css"/> </head> <body> <img class="proto mover" src="./images/logo-1024px.png"/> <div class="controls"> <button class="add"></button> <button class="subtract" disabled></button> <button class="stop">Stop</button> <button class="optimize">Optimize</button> <button class="optimize-fastdom">Optimize By Fastdom</button> <a href="https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/" target="_blank"> <button class="optimize">Help</button> </a> </div> <script src="./libs/fastdom.js"></script> <script src="index.js"></script> </body> </html>
2.使用performance除錯
為了避免chrome外掛的干擾,建議使用【隱身視窗】開啟頁面,然後開啟dev-tool,選擇Performance進行除錯
3.main執行緒的使用情況
渲染的關鍵路徑主要體現在主執行緒中,如下圖所示。
圖中的藍色的Parse HTML表示DOM的構建過程,藍色的Parse StyleSheet代表CSSOM的構建過程,黃色的Evaluate Script表示JS的執行過程,紫色的Recalculate Style表示構建Render Tree的過程,紫色的Layout表示佈局過程。
(1)單執行緒
雖然資源的下載可以並行,但是資源的解析是單執行緒的,主要通過Main執行緒來解析,由下圖所示,ParseHTML被JS的解析阻塞,分成了三段。執行緒的使用情況和程式碼中的資源的位置有很大關係,這個下面會介紹。
(2)時間線事件
Main執行緒中的圖中,有一些細線條記錄著一些事件的觸發時間,游標放在上面就可以檢視。事件主要分為Loading、Scripting、Redering、Painting四大類,具體可以檢視官方介紹。其中Scripting型別中有一種Event型別的事件,如下圖中的Event(DOMCotentLoaded)可以在JS中被監聽到,常用的還有readystatechange、pageshow、pagehide、loaded、webkitvisiblechange等,最近有一個專案中pageshow事件就幫我解決了IOS WKWebview回退頁面快取不重新整理的問題。
Tips:
(1)HTML檔案中JS檔案、CSS檔案的位置
通常我們會將css檔案放在head標籤中,JS檔案放置在body標籤的後面,這是有一定道理的。由於JS執行的過程中可能修改DOM和CSS樣式,這也就造成了Evaluate Script的執行會阻塞Parse HTML的過程,如果JS中引用未解析到的DOM程式就會報錯;如果script標籤之前有引入css檔案,Evaluate Script會等到Parse Stylesheet過程結束後再執行。
所以將CSS檔案放置在頭部,提前下載並解析;將JS檔案放在尾部,讓JS儘可能的訪問到所有的DOM,避免報錯。
(2)優化渲染路徑的重要性
前端效能優化主要分為網路請求和程式碼層面兩種。網路請求上的方法是壓縮合並、按需載入、快取等;程式碼層面則就是要優化渲染路徑,畢竟單執行緒要在模型物件構建、渲染樹構建、佈局、渲染之間切換,如下圖所示。
優化渲染路徑對於頁面效能至關重要,接下來會寫幾篇文章針對不同階段給出優化方法,敬請期待。