重排重繪與合成
阿新 • • 發佈:2020-07-06
前端有個很經典的問題是說下重排和重繪的區別,一般我們會說重排效能低,而重繪效能高。但其實我們可以深入探究一下其中但原因。
重排(迴流)
定義
當通過JS或者 CSS 修改元素的幾何屬性,例如改變元素的寬度、高度等,那麼瀏覽器會觸發重新佈局,解析之後的一系列子階段,這個過程就叫重排。無疑,重排需要更新完整的渲染流水線,所以開銷也是最大的。
圖示
觸發條件
- 新增或者刪除可見的DOM元素
- 元素位置改變
- 元素尺寸改變
- 元素內容改變(例: 一個文字被另一個不同尺寸的圖片替代)
- 頁面渲染初始化(無法避免)
- 瀏覽器視窗尺寸改變
優化方案
- 儘量不要在佈局資訊改變時做查詢(會導致渲染佇列強制重新整理)。
- 合併多次DOM操作。比如用class來改變多個樣式。
- 避免使用table。
- 使用fragment元素(createDocumentFragment)
- 讓元素脫離文件流。即讓當前元素有自己的圖層。
- 多次修改時把dom 離線 ,修改完再顯示。(display:none)
- 使用採用虛擬DOM的庫,如Vue,React
- 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
優化方案
- 合併多次操作
合成
定義
更改一個既不要佈局也不要繪製的屬性,渲染引擎將跳過佈局和繪製,只執行後續的合成操作,我們把這個過程叫做合成。比如我們使用了 CSS 的 transform 來實現動畫效果,這可以避開重排和重繪階段,直接在非主執行緒上執行合成動畫操作。這樣的效率是最高的,因為是在非主執行緒上合成,並沒有佔用主執行緒的資源,另外也避開了佈局和繪製兩個子階段,所以相對於重繪和重排,合成能大大提升繪製效率。
圖示
觸發條件
- will-change
- transform屬性改變
- 整個圖層的幾何變換,透明度變換,陰影。
優化方案
- 使用will-change提前宣告,使得渲染引擎將該元素單獨實現一幀。(空間換時間)。
⚠️:每當渲染引擎為一個元素準備一個獨立層的時候,它佔用的記憶體也會大大增加,因為從層樹開始,後續每個階段都會多一個層結構,這些都需要額外的記憶體,所以你需要恰當地使用 will-change。
參考:
極客時間:瀏覽器工作原理與實踐
https://blog.csdn.net/qq_42269433/article/details/81133772