Critical Render Path

關鍵轉譯路徑

google 其實說得很完整又很讚...

所以今天會偏向導讀,跟說一點效能相關的東西...

所以什麼是 Critical Render Path?

  • 發送請求、取得檔案、解析程式碼到繪製成螢幕上 pixel 的一連串過程

 

  • 或是也可以想像成除了我們寫的程式碼邏輯以外,瀏覽器背後在運作的機制

知道 Critical Render Path 幹啥?

  • 它跟效能有關,跟效能有關的就跟使用者體驗有關。
     
  • 或者說,有時候發現網站卡卡的,或怎麼 load 這麼久,其實關鍵轉譯路徑裡面有些步驟可以改善
     
  • 或是,有些面試官會問
     
  • 或是,之前一直在說 DOM Tree、CSS Tree,在想 webpack 為什麼要切 chunk、壓 bundle,知道 CRP 之後就會有點概念

待會要講的大方向

  • 發送請求到取得檔案
     
  • 檔案解析的流程(建構 DOM & CSSOM)
     
  • 繪製的流程簡介

發送請求到取得檔案

流程:

  1. URL 打出去
  2. 拿到 HTML 檔案
  3. 瀏覽器看一下 HTML 裡面的東西
  4. 發現有外部檔案 (JS、CSS、image 等等),再次發出請求
  5. 拿到需要的檔案

發送請求到取得檔案

發送請求到取得檔案

工程需要注意的地方:

發 request 都蠻花時間成本的。
因為過通訊協定需要時間,訊息傳輸也有物理距離所需的來回時間。
就算檔案只有 1 B,大概也要花 100 毫秒的時間。隨著檔案的大小,所需的時間也會越來越多。

 

所以我們在 webpack 會去考量每支檔案的大小,看是切出去比較省時間還是包在一起。


 

檔案解析的流程

  1. 轉換
  2. 權杖 (Tokenize)
  3. 轉成物件 (Node)
  4. 建構 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 蠻推薦閱讀

這區好像都蠻讚的

Made with Slides.com