前端性能優化(中)

圖片來自 昵圖網

性能優化調研系列文章

  1. 《前端性能優化(上)》
  2. 《前端性能優化(中)》
  3. 《前端性能優化(下)》

《前端性能優化(上)》 主要說明了:

  1. 為什么要進行前端性能優化?
  2. 如何衡量前端性能?

這一篇主要記錄了瀏覽器的加載、渲染過程的調研結果和理解。(待詳細梳理 提供動畫版本)

瀏覽器加載、渲染過程

有一道經典的前端面試題: 從輸入一個url到頁面展示發生了什么? 涉及到計算機網絡、操作系統、web等各個方面,從軟件到硬件,從協議到實現,每一個點都可以展開深入的學習,所以很考察面試者的綜合能力和某一個方面的深入掌握程度。

關于這部分知識,可以參考李兵老師的《瀏覽器原理》 課程介紹,下面的內容很大一部分 都是引用他的課程內容;另外《瀏覽器是如何工作的》也非常深入的介紹了瀏覽器工作的原理。

如果你想要有更深入的理解和掌握,建議你跟著大神一起來實現一個簡單的瀏覽器引擎

image

不聞不若聞之 聞之不若見之 見之不若知之 知之不若行之 學至于行而止矣 -- 荀子

瀏覽器架構

瀏覽器渲染流水線
進程間通信
渲染主線程

瀏覽器導航

image

圖片來源: 極客時間

  1. 瀏覽器主進程處理用戶輸入
  2. 瀏覽器主進程 通知網絡進程 發起真正的請求
  3. 網絡進程接收到請求頭信息之后 發送給瀏覽器主進程
  4. 瀏覽器主進程 接收到網絡進程發送的頭消息之后 發送“提交導航 (CommitNavigation)”消息到渲染進程
  5. 渲染進程 收到“提交導航”消息之后,直接和網絡進程建立數據管道,接受html數據
  6. 渲染進程接收html數據完成之后,會通知瀏覽器主進程:確認提交
  7. 主進程收到渲染進程的“確認提交”消息之后,就開始更新瀏覽器的狀態:loading、前進、后退、url、當前頁面
navigation timimg

以上 整個導航流程就走完了。

瀏覽器渲染流水線

一旦渲染進程發送 “確認提交”給瀏覽器主進程,就會開始解析頁面加載子資源。

  1. html parsing


    圖片來自google 文檔- 解析html
  2. 生成DOM樹


    圖片來源 google文檔- 生成DOM樹
  3. 樣式計算:Recaculate Style
    將樣式信息(來自內聯樣式、style、link等)轉換成styleSheets;
    Recaculate Style 使用所有通過css parser解析得到的style rules,包括瀏覽器給出的默認樣式,計算出每一個DOM元素最終的style的值,存儲在ComputedStyle中。

圖片來源 google文檔- 樣式計算
  1. 布局階段: 生成LayoutTree
    經過樣式計算階段之后,DOM-Tree中的節點都有了自己的樣式信息,但是還不知道如何排版,放到哪個位置。
    布局階段,就是確定繪制區域的位置和大小,相對來說也是比較復雜。
    • 對于block flow布局來說相對簡單,從上往下依次排列就好
      block flow
    • inline block


      inline-block
    • 其他更復雜的排版:文字、float、flex、table等等

總結來說,經過了布局階段之后,就生成了一個LayoutTree

layout tree

  1. paint


    google文檔-繪制
    • 我們已經通過布局階段,得到了一棵LayoutTree,現在我們已經知道了每一個Layout object的布局、顯示信息
    • 分層 生成圖層數LayerTree:z-index、3D轉換、 z-index 等會影響布局對象的顯示順序(層級)請參考 《層疊上下文》
      分層
    • 根據LayerTree,產出一個線性的繪制對象列表(列表中的每一個元素存放著繪制的顯示對象和對應的繪制操作)
    • 對于單獨的一個Layout Object,可能會包含多個顯示對象(Display Item)(如果你使用過canvas 來繪制一些東西或者使用過一些游戲引擎對這個應該比較熟悉)

輸出的display item list,會作為合成線程的輸出

current display item list: [
  {
    "chunk": "LayoutBlockFlow DIV id='example' 
        0x1b94c141c0:LayoutBlockFlow DIV id='example':DrawingPaintPhaseSelfBlockBackgroundOnly:0",
    "state": "t:0x3e697bca90 c:0x3e697ac8d0 e:0x3e697ac290",
    "displayItems": [
      {
        "index": 0,
        "clientDebugName": "InlineTextBox 'hi'",
        "id": "0x1605c60410:InlineTextBox 'hi':DrawingPaintPhaseForeground:0",
        "visualRect": "401,357 72x20",
        "opaque": false,
        "record": [
          {
            "method": "drawTextBlob",
            "params": {
              "x": 401.5,
              "y": 373,
              "paint": {
                "color": "#FF333333",
                "strokeWidth": 0,
                "strokeMiter": 4,
                "flags": "AntiAlias",
                "filterLevel": "Low",
                "strokeCap": "Butt",
                "strokeJoin": "Miter",
                "styleName": "Fill"
              }
            }
          }
        ]
      }
    ]
  }
]


  1. 光柵化
    • 渲染主線程提交 繪制列表給 合成線程;
    • 合成線程將圖層劃分為圖塊(256256 或者 512512)
    • 合成線程將圖塊提交給 柵格化線程池
    • 渲染主進程 通過柵格化線程 發送圖塊生成位圖的指令發送給GPU,
    • GPU 生成圖塊的位圖,保存在GPU內存中
    • 一旦所有圖塊都被光柵化 合成線程就會生成一個繪制圖塊的命令——“DrawQuad”,然后將該命令提交給瀏覽器進程
    • 瀏覽器進程里面有一個叫 viz 的組件,用來接收合成線程發過來的 DrawQuad 命令,然后根據 DrawQuad 命令,將其頁面內容繪制到內存中,最后再將內存顯示在屏幕上

圖片來源:極客時間

image

圖片來源 google 文檔

幾個關于渲染流水線的問題

待補充示例demo

  1. CSS 外鏈下載會阻塞 DOM 的構建嗎?
    不會, 參考demo
  1. CSS 外鏈下載會阻塞 布局樹的構建嗎?
    參考demo

  2. CSS外鏈文件下載會阻塞后面的js的下載嗎?
    不會,現代瀏覽器會在收到html文檔之后預解析,請求所有的資源


    image.png
  3. CSS外鏈文件下載會阻塞js的執行嗎?


    css的下載阻塞了js的執行
  4. js文件的下載和執行會阻塞 DOM樹的構建嗎?

參考

  1. Let's build a browser engine!

  2. 《瀏覽器原理》

  3. 《瀏覽器是如何工作的》

  4. How Blink works

  5. life of pixel

  6. chrome university

  7. Inside a super fast CSS engine: Quantum CSS

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容