Critical Render Path
關鍵轉譯路徑
google 其實說得很完整又很讚...
所以今天會偏向導讀,跟說一點效能相關的東西...
所以什麼是 Critical Render Path?
- 發送請求、取得檔案、解析程式碼到繪製成螢幕上 pixel 的一連串過程
- 或是也可以想像成除了我們寫的程式碼邏輯以外,瀏覽器背後在運作的機制
知道 Critical Render Path 幹啥?
- 它跟效能有關,跟效能有關的就跟使用者體驗有關。
- 或者說,有時候發現網站卡卡的,或怎麼 load 這麼久,其實關鍵轉譯路徑裡面有些步驟可以改善
- 或是,有些面試官會問
- 或是,之前一直在說 DOM Tree、CSS Tree,在想 webpack 為什麼要切 chunk、壓 bundle,知道 CRP 之後就會有點概念
待會要講的大方向
- 發送請求到取得檔案
- 檔案解析的流程(建構 DOM & CSSOM)
- 繪製的流程簡介
發送請求到取得檔案
流程:
- URL 打出去
- 拿到 HTML 檔案
- 瀏覽器看一下 HTML 裡面的東西
- 發現有外部檔案 (JS、CSS、image 等等),再次發出請求
- 拿到需要的檔案
發送請求到取得檔案
發送請求到取得檔案
工程需要注意的地方:
發 request 都蠻花時間成本的。
因為過通訊協定需要時間,訊息傳輸也有物理距離所需的來回時間。
就算檔案只有 1 B,大概也要花 100 毫秒的時間。隨著檔案的大小,所需的時間也會越來越多。
所以我們在 webpack 會去考量每支檔案的大小,看是切出去比較省時間還是包在一起。
檔案解析的流程
- 轉換
- 權杖 (Tokenize)
- 轉成物件 (Node)
- 建構 DOM
檔案解析的流程
除了 DOM 之外,CSS 也會有相同的過程,建構出 CSSOM(CSS Object Modal)
檔案解析的流程
最終會把 DOM & CSSOM 合併成 Render Tree。
有了 Render Tree 才會開始真的繪製圖面到我們的螢幕上
檔案解析的流程
跟效能有關的地方:瀏覽器建構的順序
- DOM 跟 CSSOM 沒有完成建構之前,不會有畫面
- 因為 JS 內容會影響 DOM 跟 CSS,所以 HTML 中碰到 JS 相關的行數,會暫停上面兩個的建構,而先解析 JS
- 解析 JS 的時候,如果碰到樣式有關的操作,如果這時發現 CSSOM 還沒建構完,就會先去處理 CSS,再來是 JS,最後才繼續建構 DOM
檔案解析的流程
結論是:
儘早開始解析 CSS、JS 最晚,讓 DOM 跟 CSSOM 可以先處理
<!DOCTYPE html>
<html lang="en">
<head>
<link href="myStyle.css" rel="stylesheet">
</head>
<body>
<div>
<p>
<span></span>
</p>
</div>
<script src="myJs.js"></script>
</body>
</html>
繪製的流程
繪製的流程:
Scripting (爬扣)
Rendering(更新 data)
Painting(實際更新畫面 pixel)
繪製的流程
所以 performance 那頁才會長這樣
繪製的流程
跟繪製有關的效能考量: re-flow / layout thrashing
這兩個短時間進行大量的更新
繪製的流程
什麼會觸發 re-flow:
繪製的流程
什麼情況會觸發 re-flow:
read or write 那些東西的時候
var heightA = elementA.offsetHeight; // read
elementB.offsetHeight = 200; // write
繪製的流程
什麼時候 re-flow 的代價很高:
更新 DOM 或 CSSOM 之後再讀取或寫入上述數值,可以想像首次 render 要做的事情,都要再做一遍
繪製的流程
別人的範例:
var UpdateThrash = function(data) {
var spans = document.querySelectorAll('.item .lab');
var colWidth = 0;
for (var i = 0; i < spans.length; i++) {
var span = spans[i];
span.style.fontSize = '14.1px';
colWidth = Math.max(colWidth, span.offsetWidth);
}
};
var UpdateNoThrash = function(data) {
var spans = document.querySelectorAll('.item .lab');
for (var i = 0; i < spans.length; i++) {
var span = spans[i];
span.style.fontSize = '14.0px';
}
var colWidth = 0;
for (var i = 0; i < spans.length; i++) {
var span = spans[i];
colWidth = Math.max(colWidth, span.offsetWidth);
}
};
導讀完畢,後面的 reference 蠻推薦閱讀
這區好像都蠻讚的
Critical Render Path
By Kai Ting Liu
Critical Render Path
- 307