重排與重繪

原文地址:http://www.cun-xu.cn/index.ph...php

在頁面的生命週期中,一些效果的交互都有可能發生重排(Layout)和重繪(Painting),這些都會使咱們付出高額的性能代價。
瀏覽器從下載文件至本地到顯示頁面是個複雜的過程,這裏包含了重繪和重排。一般來講,渲染引擎會解析HTML文檔來構建DOM樹,與此同時,渲染引擎也會用CSS解析器解析CSS文檔構建CSSOM樹。接下來,DOM樹和CSSOM樹關聯起來構成渲染樹(RenderTree),這一過程稱爲Attachment。而後瀏覽器按照渲染樹進行佈局(Layout),最後一步經過繪製顯示出整個頁面。css

渲染過程

其中重排和重繪是最耗時的部分,一旦觸發重排,咱們對DOM的修改引起了DOM幾何元素的變化,渲染樹須要從新計算,
而重繪只會改變vidibilityoutline、背景色等屬性致使樣式的變化,使瀏覽器須要根據新的屬性進行繪製。更比而言,重排會產生比重繪更大的開銷。因此,咱們在實際生產中要嚴格注意減小重排的觸發。瀏覽器

觸發重排的操做主要是幾何因素:

1.頁面第一次渲染
在頁面發生首次渲染的時候,全部組件都要進行首次佈局,這是開銷最大的一次重排。
2.瀏覽器窗口尺寸改變
3.元素位置和尺寸發生改變的時候
4.新增和刪除可見元素
5.內容發生改變(文字數量或圖片大小等等)
6.元素字體大小變化。
7.激活CSS僞類(例如::hover)。
8.設置style屬性
9.查詢某些屬性或調用某些方法。好比說:緩存

offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeightdom

除此以外,當咱們調用getComputedStyle方法,或者IE裏的currentStyle時,也會觸發重排,原理是同樣的,都爲求一個「即時性」和「準確性」。ide

觸發重繪的操做主要有:

vidibilityoutline、背景色等屬性的改變佈局

咱們應當注意的是:重繪不必定致使重排,但重排必定會致使重繪。性能

那麼咱們能夠採起哪些措施來避免或減小重排帶來的巨大開銷呢?
1.分離讀寫操做
div.style.top = "10px";
div.style.bottom = "10px";
div.style.right = "10px";
div.style.left = "10px";
console.log(div.offsetWidth);
console.log(div.offseHeight);
console.log(div.offsetRight);
console.log(div.offsetLeft);

原來的操做會致使四次重排和四次重繪,變換順序以後只會觸發一次重排
在第一個console的時候,瀏覽器把以前上面四個寫操做的渲染隊列都給清空了。由於渲染隊列原本就是空的,因此剩下的console並無觸發重排,僅僅拿值而已。字體

2.樣式集中改變

經過classcssText進行集中改變樣式
未進行優化的代碼是這樣的:優化

//bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top = top + "px";

雖然如今大部分現代瀏覽器都會有Flush隊列進行渲染隊列優化,可是有些老版本的瀏覽器好比IE6這樣的坑貨效率依然低下:
這時咱們就能夠經過上面所說的利用classcssText屬性集中改變樣式

//good
el.className += " className";
//or
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
3. 緩存佈局信息
// bad 強制刷新 觸發兩次重排
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';

// good 緩存佈局信息 至關於讀寫分離
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
複製代碼
4. 將DOM離線
  • DOM離線化

一旦咱們給元素設置display:none時,元素不會存在於渲染樹中,至關於將其從頁面「拿掉」,咱們以後的操做將不會觸發重排和重繪,這叫作DOM的離線化。

dom.display = 'none'
// 修改dom樣式
dom.display = 'block'
複製代碼
  • 經過使用DocumentFragment建立一個dom碎片,在它上面批量操做dom,操做完成以後,再添加到文檔中,這樣只會觸發一次重排。
  • 複製節點,在副本上工做,而後替換它!
5. 將position屬性設置爲absolutefixed

position屬性爲absolutefixed的元素,重排開銷比較小,不用考慮它對其餘元素的影響

6. 優化動畫
  • 能夠把動畫效果應用到position屬性爲absolutefixed的元素上,這樣對其餘元素影響較小

動畫效果還應犧牲一些平滑,來換取速度,這中間的度本身衡量:

好比實現一個動畫,以1個像素爲單位移動這樣最平滑,可是Layout就會過於頻繁,大量消耗CPU資源,若是以3個像素爲單位移動則會好不少。

  • 啓用GPU加速

GPU 硬件加速是指應用 GPU 的圖形性能對瀏覽器中的一些圖形操做交給 GPU 來完成,由於 GPU 是專門爲處理圖形而設計,因此它在速度和能耗上更有效率。

GPU 加速一般包括如下幾個部分:Canvas2D,佈局合成, CSS3轉換(transitions),CSS3 3D變換(transforms),WebGL和視頻(video)。

/*
* 根據上面的結論
* 將 2d transform 換成 3d
* 就能夠強制開啓 GPU 加速
* 提升動畫性能
*/
div {
transform: translate3d(10px, 10px, 0);
}

娘滴,終於寫完了,肩膀子疼的我,得要得肩周炎了。

相關文章
相關標籤/搜索