1. 程式人生 > >重排重繪與合成

重排重繪與合成

前端有個很經典的問題是說下重排和重繪的區別,一般我們會說重排效能低,而重繪效能高。但其實我們可以深入探究一下其中但原因。

重排(迴流)

定義

當通過JS或者 CSS 修改元素的幾何屬性,例如改變元素的寬度、高度等,那麼瀏覽器會觸發重新佈局,解析之後的一系列子階段,這個過程就叫重排。無疑,重排需要更新完整的渲染流水線,所以開銷也是最大的。

圖示

觸發條件

  • 新增或者刪除可見的DOM元素
  • 元素位置改變
  • 元素尺寸改變
  • 元素內容改變(例: 一個文字被另一個不同尺寸的圖片替代)
  • 頁面渲染初始化(無法避免)
  • 瀏覽器視窗尺寸改變

優化方案

  1. 儘量不要在佈局資訊改變時做查詢(會導致渲染佇列強制重新整理)。
  2. 合併多次DOM操作。比如用class來改變多個樣式。
  3. 避免使用table。
  4. 使用fragment元素(createDocumentFragment)
  5. 讓元素脫離文件流。即讓當前元素有自己的圖層。
  6. 多次修改時把dom 離線 ,修改完再顯示。(display:none)
  7. 使用採用虛擬DOM的庫,如Vue,React
  8. will-change: transform 啟用硬體加速

 

重繪

定義

當通過JS或者 CSS 修改元素的繪製屬性,例如改變元素的背景顏色,那麼佈局階段將不會被執行,因為並沒有引起幾何位置的變換,所以就直接進入了繪製階段(即生成待繪製列表),然後執行之後的一系列子階段,這個過程就叫重繪。相較於重排操作,重繪省去了佈局和分層階段,所以執行效率會比重排操作要高一些。

圖示

觸發條件

  • background屬性(background,background-color,background-image,background-position,background-repeat,background-size)
  • outline屬性(outline,outline-color,outline-style)
  • box-shadow屬性
  • border屬性(border-style,border-radius)
  • visibility

優化方案

  1. 合併多次操作

 

合成

定義

更改一個既不要佈局也不要繪製的屬性,渲染引擎將跳過佈局和繪製,只執行後續的合成操作,我們把這個過程叫做合成。比如我們使用了 CSS 的 transform 來實現動畫效果,這可以避開重排和重繪階段,直接在非主執行緒上執行合成動畫操作。這樣的效率是最高的,因為是在非主執行緒上合成,並沒有佔用主執行緒的資源,另外也避開了佈局和繪製兩個子階段,所以相對於重繪和重排,合成能大大提升繪製效率。

圖示

觸發條件

  • will-change
  • transform屬性改變
  • 整個圖層的幾何變換,透明度變換,陰影。

優化方案

  1. 使用will-change提前宣告,使得渲染引擎將該元素單獨實現一幀。(空間換時間)。

⚠️:每當渲染引擎為一個元素準備一個獨立層的時候,它佔用的記憶體也會大大增加,因為從層樹開始,後續每個階段都會多一個層結構,這些都需要額外的記憶體,所以你需要恰當地使用 will-change。

 

參考:

極客時間:瀏覽器工作原理與實踐

https://blog.csdn.net/qq_42269433/article/details/81133772