瞭解重排與重繪

重繪和重排操作都是代價昂貴的操作,它們會導致web應用程序的UI反應遲鈍,所以應該儘可能減少這類過程的發生。下面我們來簡單瞭解一下

前言

瀏覽器下載完頁面中的所有內容:HTML、JavaScript、CSS、圖片——之後會解析並生成兩個內部數據結構:

  • DOM樹:表示頁面結構
  • 渲染樹:表示DOM節點如何顯示

DOM樹中的每一個需要顯示的節點在渲染樹中至少存在一個對應的節點(隱藏的DOM元素在渲染樹中沒有對應的節點)。渲染樹中的節點被稱爲“幀”或者“盒子”,理解頁面元素爲一個具有填充(padding)、邊距(margin)、邊框(border)和位置(position)的盒子。一旦DOM樹和渲染樹構建完成,瀏覽器就開始顯示(繪製 paint)頁面元素

當DOM的改變影響了元素幾何屬性(例如寬和高)——瀏覽器就需要重新計算元素的幾何特性,同樣其他元素的幾何屬性和位置也會因此受到影響。瀏覽器會使渲染樹中受到影響的部分失效,並重新構造渲染樹。這個過程稱爲重排(reflow)。完成重排後,瀏覽器會重新繪製受到影響的部分到屏幕中,該過程稱爲重繪(repaint)

重繪和重排操作都是代價昂貴的操作,它們會導致web應用程序的UI反應遲鈍,所以應該儘可能減少這類過程的發生。

引起重排的原因

  • 添加或刪除可見的DOM元素
  • 元素位置改變
  • 元素尺寸改變
  • 內容改變(例如:文本改變或圖片被另一個不同尺寸的圖片替代)
  • 頁面渲染初始化
  • 瀏覽器窗口尺寸改變

渲染樹變化的排隊與刷新

由於每次重排都會產生計算消耗,大多數瀏覽器通過隊列化修改和批量執行來優化重排過程(將多個重排過程合併成一次)。然而,某些操作會強制刷新隊列並要求隊列中的重排立即執行(這樣會使瀏覽器的優化策略失效)。

  • 獲取佈局信息的操作會導致強制刷新隊列,使得瀏覽器不得不執行渲染隊列中的“待處理變化”並觸發重排以返回正確的值
    • offsetTop,offsetLeft,offsetWidth,offsetHeight
    • scrollTop,scrollLeft,scrollWidth,scrollHeight
    • clientTop,clientLeft,clientWidth,clientHeight
    • getComputedStyle()
  • 優化方法:儘量不要在佈局信息改變時查詢它,可以在佈局信息改變完畢之後再去查詢

最小化重繪和重排

重繪和重排的代價非常昂貴,因此一個好的提高程序響應速度的策略就是減少此類操作的發生。爲了減少發生次數,應該合併多次對DOM和樣式的修改,然後一次處理掉。

合併多次對樣式的修改

var el = document.getElementById('myDiv')
el.style.borderLeft = '1px'
el.style.borderRight = '2px'
el.style.padding = '5px'

上面的例子中,存在兩個問題:

  • 每個樣式屬性的改變都會影響元素的集合結構,最糟糕的情況下,會導致瀏覽器觸發三次重排(大部分現代瀏覽器都爲此做了優化,只會觸發一次重排)
  • 上面的代碼訪問了4次DOM

優化方法:使用cssText屬性,合併所有的改變然後一次處理

var el = document.getElementById('myDiv')
el.style.cssText +='border-left: 1px; border-right: 2px; padding: 5px;';

批量修改DOM

當需要對DOM元素進行一系列操作時,可以通過以下步驟來減少重繪和重排的次數

1.使元素脫離文檔流

2.對其進行一些列操作

3.把元素帶回文檔中

  • 使元素脫離文檔流的方法:
    • 隱藏元素,施加修改,重新顯示
    • 使用document fragment在當前DOM之外構建一個子樹,再把它拷貝會文檔
    • 將元素元素拷貝到另一個脫離文檔的節點中,修改副本,完成後再替換原始元素。

緩存佈局信息

在上面的介紹中講到了,瀏覽器通過隊列化修改和批量執行的方式減少重排次數。但是當查詢佈局信息時(如獲取偏移量、滾動位置、計算出的樣式值),瀏覽器爲了返回最新值,會刷新隊列並應用所有的變更。因此最好的做法應該是儘量減少佈局信息的獲取次數,獲取後把它複製給局部變量,然後再操作局部變量。

IE和:hover

避免在大量元素上使用:hover這種效果。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

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