首先我們要明確頁面在文件載入完成之後到完全顯示中間的過程是1.根據文件生成dom樹(包括display:none的節點)2.在dom樹基礎上根據節點的幾何屬性(margin/padding/width/height等)生成render樹(不包括display:none、head節點但會包含visibility:hidden節點)3.在render樹基礎上進行進一步渲染包括color,outline等樣式
r ef
low:
當ren
der樹
中的一部
分或者全
部因為大
小邊距等
問題發生
改變而需
要重建的
過程叫做
回流
\color
reflow
:當re
nder
樹中的一
部分或者
全部因為
大小邊距
等問題發
生改變而
需要重建
的過程叫
做回流rep
aint
:當元素
的一部分
屬性發生
變化,如
外觀背景
色不會引
起布局變
化而需要
重新渲染
的過程叫
做重
繪\color
repain
t:當元
素的一部
分屬性發
生變化,
如外觀背
景色不會
引起布局
變化而需
要重新渲
染的過程
叫做重繪
這個問題其實很簡單,什麼引起的,看定義不就可以了?
問題是引起的原因可能會很多
籠統來說當頁面的布局和幾何屬性發生變化的時候就會引起回流。具體來說大概分別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.
(document.
createtextnode
('abc!'))
;
現在我們大概都能得出的結論是:回流比重繪的代價要高,至於具體的花銷跟render樹有多少節點需要重新構建有關。
還有就是,回流一定會伴隨著重繪,但是重繪不一定會引起回流。
從上面的例項**中可以看到一共七行**引起了6次左右的回流、重繪(上面的**我大老遠從別的頁面拿過來當然不只是就用那一次,哈哈),而且我們剛剛還知道了回流花銷真是不小,那麼瀏覽器是不是真的每次js語句引起了回流他就執行一下呢?恩,後面的內容我是看的參考資料的:等佇列中的操作到了一定的數量或者到了一定的時間間隔,瀏覽器就會flush佇列,進行乙個批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。
但是儘管瀏覽器挺機智地幫我們優化了**,我們自己作死也是沒救的,比如你去請求
offsettop, offsetleft, offsetwidth, offsetheight
scrolltop/left/width/height
clienttop/left/width/height
width,height
請求了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倍於同等元素的時間。
Reflow 回流 和Repaint 重繪
首先我們要明白的是,頁面的顯示過程分為以下幾個階段 1 生成dom樹 包括display none的節點 2 在dom樹的基礎上根據節點的集合屬性 margin,padding,width,height等 生成render樹 不包括display none,head節點,但是包括visibility...
回流 reflow 和重繪 repaint
首先先介紹瀏覽器解析的工作原理 1.解析html文件建立dom樹 2.解析css 包含外部css以及js生成的 構建渲染樹,計算出節點的樣式 3.布局渲染樹,以根節點遞迴呼叫,計算每乙個節點的大小,位置等,給出每乙個節點出現在螢幕的精準目標 4.繪製渲染樹,遍歷渲染樹,每個幾點使用ui後端層來繪製 ...
reflow 回流 和repaint 重繪
dom節點中的各個元素都是以盒模型的形式存在,這些都需要瀏覽器去計算其位置和大小等,這個過程稱為reflow 當盒模型的位置,大小以及其他屬性,如顏色,字型,等確定下來之後,瀏覽器便開始繪製內容,這個過程稱為repaint。頁面在首次載入時必然會經歷reflow和repaint。reflow和rep...