js - 重繪與迴流

DOM樹和樣式結構體 (瀏覽器所能識別的所有樣式) 構建組成渲染樹 (render tree) 來完成繪製頁面 

當渲染樹的一部分發生改變, 若只引起頁面的非佈局外觀 (如背景等) 發生改變時, 那這就是一次頁面重繪(repaint)

若引起頁面的佈局發生改變, 那這就是一次頁面迴流 (reflow), 同時頁面外觀也發生改變, 意味着必然伴隨重繪

 

  • 迴流

添加/刪除元素
display: none;
定位, 浮動, 邊距等改變位置
改變盒模型
改變文字大小, 粗細, 位置, 間隔, 行高, 超出容器處理方式等
改變瀏覽器大小
激活僞類 (:hover)
內容變化 (input等輸入文字)

 

  • 重繪

改變 visiblility, z-index, 輪廓, 顏色, 背景, 陰影等

 

迴流的代價遠比重繪昂貴, 很大程度影響着頁面性能, 減緩JavaScript
而這裏要做的就是規避迴流, 降低迴流造成的影響, 降低迴流需要的成本

 

  • 規避DOM的頻繁訪問

切換和彈窗, 實際中這樣的操作不只是一次, 而這裏要說的是其中的迴流成本

如 $(button) -> $.show(dialog), 相當於每次操作都要先訪問DOM的"button"和"dialog"

變量存儲, 將頻繁操作的元素作爲變量

避免用類名或樣式屬性來作爲條件判斷

 

  • 規避頻繁影響DOM

將多個元素打包再添加到DOM

加入DOM前, 先賦予屬性內容等

將需要改變的多個樣式封裝到一個類裏, 然後只要改變className
若樣式的屬性值是動態的, 可以用cssText

 

  • 減少對其它元素的影響

文檔流中, 在其它元素後添加內容

動態改變位置或盒模型, 會影響其它元素的, 建議用定位處理

圖片設置寬高, 避免頁面加載後, 再繪製高度, 影響其它元素

 

  • 規避頁面刷新或訪問新頁面

頁面加載時, 瀏覽器會把所有引起迴流的操作在構建渲染樹前排入一個隊列, 並在出隊列時批量處理, 然後執行一次頁面繪製, 使這過程只發生一次迴流

問題不僅是繪製頁面的, 還包括繪製頁面前的高昂成本

更新局部內容, 替代刷新頁面

同頁面中加載數據並展示新內容, 替代在打開新頁面

當要訪問佈局上的迴流數據, 如窗口大小等, 樣式中的盒模型, 偏移量等屬性, 瀏覽器同樣將這些迴流操作提前處理一遍, 然後執行一次頁面繪製, 伴隨一次頁面迴流

 

  • 動畫優化

瀏覽器會在主線程外爲執行CSS3動畫的節點創建一個圖層, 並把節點移到圖層上, 然後通過CPU或GPU將同一個動畫的每個節點所創建的圖層組合成一個圖層添加到頁面, 最後執行動畫, 這過程把節點移到圖層上時產生了一個迴流, 這個迴流讓同一個動畫的每個節點都消失

把圖層添加到頁面又產生了一個迴流, 這個迴流花費的時間基本決定了動畫開始前的準備時間, 如果所花的時間較長, 就會看到這些節點消失的瞬間, 如果用CPU處理 (CPU處理圖層不及GPU), 所花的時間會更長

可想可知, transform 和 opacity 的動畫過程沒有迴流, 但動畫前卻是一場噩夢

 開啓設備硬件加速渲染, 即強制使用GPU進行2D繪圖

用 translateZ() 或 translate3d() 代替 translate() 從而提高CPU的處理減少動畫開始前的準備時間, 且不會隨着抗鋸齒而導出突變

但依舊免不了迴流所耗的時間, 而且過多 translateZ() 或 translate3d() 佔用CPU使用率, 將導致CPU性能下降

 

犧牲平滑度換取速度

每次1px移動一個動畫, 可能導致動畫及隨後的迴流佔用了很高的CPU使用率, 動畫就會看上去是跳動的, 因爲瀏覽器正在與更新迴流做鬥爭

動畫元素每次移動3px可能在非常快的機器上看起來平滑度低了, 但它不會導致在CPU較慢的機器和移動設備中抖動

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章