此內容均爲借鑑,提煉。編程
現代瀏覽器一般擁有兩個重要的執行線程,這兩個線程相互配合來渲染出頁面:主線程 與 排版線程瀏覽器
主線程:
- 運行JavaScript
- 計算HTML元素的CSS樣式
- 佈局頁面
- 把頁面元素繪製成一個或多個位圖
- 把這些位圖移交給排版線程
排版線程:
- 經過GPU渲染位圖,並顯示在屏幕上
- 向主線程請求更新位圖的可見部分或即將可見的部分
- 判斷出當前頁面處於可見的部分
- 判斷出即將經過頁面滾動而可見的部分
- 隨着用戶滾動頁面來移動這些部分(可見部分的和即將可見的部分)
GPU:
- 排版線程經過GPU把位圖繪製到了屏幕上。
- GPU比較擅長於:繪製位圖到屏幕、重複的繪製同一個位圖、在不一樣的位置,以不一樣的旋轉角度,或者不一樣的縮放大小來繪製同一個位圖。
- GPU相對慢的地方:將位圖加載到顯存裏。
重排與重繪:
瀏覽器下載完頁面中的全部組件——HTML標記、JavaScript、CSS、圖片以後會解析生成兩個內部數據結構——DOM樹和渲染樹。數據結構
- DOM樹表示頁面結構,渲染樹表示DOM節點如何顯示。
- 當DOM的變化影響了元素的幾何屬性(寬或高),瀏覽器須要從新計算元素的幾何屬性,一樣其餘元素的幾何屬性和位置也會所以受到影響。瀏覽器會使渲染樹中受到影響的部分失效,並從新構造渲染樹。這個過程稱爲重排。完成重排後,瀏覽器會從新繪製受影響的部分到屏幕,該過程稱爲重繪。
tips:並非全部的DOM變化都會影響幾何屬性,好比改變一個元素的背景色並不會影響元素的寬和高,這種狀況下只會發生重繪。佈局
引發重排的狀況:
很顯然,每次重排,必然會致使重繪,那麼,重排會在哪些狀況下發生?性能
- 添加或者刪除可見的DOM元素
- 元素位置改變
- 元素尺寸改變
- 元素內容改變(例如:一個文本被另外一個不一樣尺寸的圖片替代)
- 頁面渲染初始化(沒法避免)
- 瀏覽器窗口尺寸改變
這些都是顯而易見的,或許你已經有過這樣的體會,不間斷地改變瀏覽器窗口大小,致使UI反應遲鈍(某些低版本IE下甚至直接掛掉),如今你可能恍然大悟,沒錯,正是一次次的重排重繪致使的!動畫
Transition:
在整個Transition的每一幀中,瀏覽器都要去從新佈局,繪製頁面,並把最新的位圖對象加載到GPU。
設計決策:
那麼,是否這就意味這咱們不要去緩動一個元素的高度?非也,一些狀況下,這是你的設計效果的一部分,而且動畫效果能夠很是快的完成。也許動畫的元素是孤立的,不會引發頁面其餘部分進行從新佈局;也許該元素只是單純的進行重繪,瀏覽器能夠快速的完成;也許該元素很小,瀏覽器只需將很小的位圖對象傳遞給GPU。
固然了,在不影響你設計的視覺效果的狀況下,最好去緩動一個性能較好的CSS屬性,如transform,而不是去緩動一個性能較差的CSS屬性,如height。舉例來講,假設你的設計中有一個按鈕,當點擊它的時候會出來一個菜單,試着去緩動菜單的transform屬性來顯示它而不是緩動它的top或height屬性來達到相似的效果。
在動畫上特別快的CSS屬性包括:spa
- CSS transform
- CSS opacity
- CSS filter
總結
重排和重繪是DOM編程中耗能的主要緣由之一,平時涉及DOM編程時能夠參考如下幾點:線程
- 儘可能不要在佈局信息改變時作查詢(會致使渲染隊列強制刷新)
- 同一個DOM的多個屬性改變能夠寫在一塊兒(減小DOM訪問,同時把強制渲染隊列刷新的風險降爲0)
- 若是要批量添加DOM,能夠先讓元素脫離文檔流,操做完後再帶入文檔流,這樣只會觸發一次重排(fragment元素的應用)
- 將須要屢次重排的元素,position屬性設爲absolute或fixed,這樣此元素就脫離了文檔流,它的變化不會影響到其餘元素。例若有動畫效果的元素就最好設置爲絕對定位。