迴流(reflow)與重繪(repaint)

最近項目排期不緊,因而看了一下以前看了很久也沒看明白的chrome調試工具的timeline。可是很遺憾,雖然大概懂了每一項是作什麼的,可是用起來並不能駕輕就熟。因此今天的重點不是timeline,而是我在看timeline的時候發現的reflow.reflow,迴流。什麼是迴流呢?看了好多文章都提到迴流與重繪會影響頁面性能,每次這兩個都會被同時說起,關係就好像KFC邊上必定會有MC同樣親密的讓人摸不到頭腦。而後看了許多資料以後終於有了本身的認知,先列出個人參考文章javascript

http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/comment-page-1/css

http://www.css88.com/archives/4991java

http://www.css88.com/archives/4996node

下面的內容是我看過這些資料以後本身的一些理解及總結。chrome

一.明確概念瀏覽器

首先咱們要明確頁面在文檔加載完成以後到徹底顯示中間的過程是1.根據文檔生成DOM樹(包括display:none的節點)2.在DOM樹基礎上根據節點的幾何屬性(margin/padding/width/height等)生成render樹(不包括display:none、head節點但會包含visibility:hidden節點)3.在render樹基礎上進行進一步渲染包括color,outline等樣式緩存

reflow:當render樹中的一部分或者所有由於大小邊距等問題發生改變而須要重建的過程叫作迴流app

repaint:當元素的一部分屬性發生變化,如外觀背景色不會引發佈局變化而須要從新渲染的過程叫作重繪dom

二.什麼會引發迴流工具

個問題其實很簡單,什麼引發的,看定義不就能夠了?

問題是引發的緣由可能會不少

籠統來講當頁面的佈局和幾何屬性發生變化的時候就會引發迴流。具體來講大概分別5大類:

1.首當其衝天然是dom樹結構變化,好比你刪除或者添加某個node.

2.元素幾何屬性變化,包括margin,padding,height,width,border等

3.頁面渲染初始化

4.獲取某些屬性。雖然瀏覽器引擎可能會針對重排作了優化,好比Opera,它會等到有足夠 數量的變化發生,或者等到必定的時間,或者等一個線程結束,再一塊兒處理,這樣就只發生一次重排。但除了render樹的直接變化,當獲取一些屬性時,瀏覽器爲取得 正確的值也會觸發迴流。這樣就使得瀏覽器的優化失效了。這些屬性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、 clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。因此,在屢次使用這些值時應進行緩存。(這段我是直接引用的。。。)

5.瀏覽器窗口發生變化-resize事件發生時

以上,其實理解起來很容易。所謂的render樹就是識別了幾何屬性的dom數,好像咱們畫人體的時候,dom樹是先肯定都有什麼好比四肢,頭部,身體,其餘器官等;而render樹則是肯定這我的的高矮胖瘦,頭髮是否蓋眼睛等,若是咱們在繪畫過程當中發現脖子長了那就慘了,脖子下面都要重畫。這就是迴流了。若是發現只是手指畫的有問題也仍是要回流但咱們只須要重畫手指。(固然,我說的是手就是手,沒什麼特別造型的時候);當咱們的render樹完事了,也就是人體大概輪廓咱們都畫好了,就能夠上色了,換個髮色這種咱們叫重繪。

var s = document.body.style;
s.padding = "2px"; // 迴流+重繪
s.border = "1px solid red"; // 再一次 迴流+重繪
s.color = "blue"; // 再一次重繪
s.backgroundColor = "#ccc"; // 再一次 重繪
s.fontSize = "14px"; // 再一次 迴流+重繪
// 添加node,再一次 迴流+重繪
document.body.appendChild(document.createTextNode('abc!'));

  如今咱們大概都能得出的結論是:迴流比重繪的代價要高,至於具體的花銷跟render樹有多少節點須要從新構建有關。

  還有就是,迴流必定會伴隨着重繪,可是重繪不必定會引發迴流。

3、咱們要如何避免

從上面的實例代碼中能夠看到一共七行代碼引發了6次左右的迴流、重繪(上面的代碼我大老遠從別的頁面拿過來固然不僅是就用那一次,哈哈),並且咱們剛剛還知道了迴流花銷真是不小,那麼瀏覽器是否是真的每次js語句引發了迴流他就執行一下呢?恩,後面的內容我是看的參考資料的:等隊列中的操做到了必定的數量或者到了必定的時間間隔,瀏覽器就會flush隊列,進行一個批處理。這樣就會讓屢次的迴流、重繪變成一次迴流重繪。

可是儘管瀏覽器挺機智地幫咱們優化了代碼,咱們本身做死也是沒救的,好比你去請求

1. offsetTop, offsetLeft, offsetWidth, offsetHeight

2. scrollTop/Left/Width/Height

3. clientTop/Left/Width/Height

4. width,height

5. 請求了getComputedStyle(), 或者 IE的 currentStyle

瀏覽器爲了給你返回一個比較精確的答案,他會提早flush隊列,由於隊列中可能會有影響這些值的操做。

因此咱們能夠作的是: 

1.將那些改變樣式的操做集合在一次完事,直接改變className或者cssText

2.讓要操做的元素進行離線處理,處理完事之後再一塊兒更新

(1)使用DocumentFragment進行緩存操做,引起一次迴流和重繪

課外延伸

DocumentFragment 節點不屬於文檔樹,繼承的 parentNode 屬性老是 null。

不過它有一種特殊的行爲,該行爲使得它很是有用,即當請求把一個 DocumentFragment 節點插入文檔樹時,插入的不是 DocumentFragment 自身,而是它的全部子孫節點。這使得 DocumentFragment 成了有用的佔位符,暫時存放那些一次插入文檔的節點。它還有利於實現文檔的剪切、複製和粘貼操做。

其實他就是一個遊離在DOM樹外面的容器,因此你在把它插入文檔節點以前,隨便給他增刪節點都不會引發迴流

(2)使用display:none,只引起兩次迴流和重繪。道理跟上面的同樣。由於display:none的元素不會出如今render樹

(3)使用cloneNode和replaceChild技術,引起一次迴流和重繪(這條其實沒太明白)

3.不要常常訪問會引發瀏覽器flush隊列的屬性,非要高頻訪問的話建議緩存到變量;

4.將須要屢次重排的元素,position屬性設爲absolute或fixed,這樣此元素就脫離了文檔流,它的變化不會影響到其餘元素。例若有動畫效果的元素就最好設置爲絕對定位;

5.儘可能不要使用表格佈局,若是沒有定寬表格一列的寬度由最寬的一列決定,那麼極可能在最後一行的寬度超出以前的列寬,引發總體迴流形成table可能須要屢次計算才能肯定好其在渲染樹中節點的屬性,一般要花3倍於同等元素的時間。

4、總結

別人這個地方都是列了一下實驗結果,鑑於個人timeline還用不明白就不獻醜了。

若有錯誤之處,歡迎指正。

最後再強調一下,以上內容參考了文章開頭列出的資料,若有雷同,那很正常。。。

相關文章
相關標籤/搜索