重繪(redraw或repaint),重排(reflow)


瀏覽器運行機制圖:

瀏覽器的運行機制layout:布局;

1、構建DOM樹(parse):渲染引擎解析HTML文檔,首先將標簽轉換成DOM樹中的DOM node(包括js生成的標簽)生成內容樹(Content Tree/DOM Tree);

2、構建渲染樹(construct):解析對應的CSS樣式文件信息(包括js生成的樣式和外部css文件),而這些文件信息以及HTML中可見的指令(如<b></b>),構建渲染樹(Rendering Tree/Frame Tree);

3、布局渲染樹(reflow/layout)從根節點遞歸調用,計算每一個元素的大小、位置等,給出每個節點所應該在屏幕上出現的精確坐標;

4、繪制渲染樹(paint/repaint)遍歷渲染樹,使用UI后端層來繪制每個節點。

重繪(repaint或redraw):當盒子的位置、大小以及其他屬性,例如顏色、字體大小等都確定下來之后,瀏覽器便把這些原色都按照各自的特性繪制一遍,將內容呈現在頁面上。

            重繪是指一個元素外觀的改變所觸發的瀏覽器行為,瀏覽器會根據元素的新屬性重新繪制,使元素呈現新的外觀。

   觸發重繪的條件:改變元素外觀屬性。如:color,background-color等。

注意:table及其內部元素可能需要多次計算才能確定好其在渲染樹中節點的屬性值,比同等元素要多花兩倍時間,這就是我們盡量避免使用table布局頁面的原因之一。

重排(重構/回流/reflow):當渲染樹中的一部分(或全部)因為元素的規模尺寸,布局,隱藏等改變而需要重新構建, 這就稱為回流(reflow)。每個頁面至少需要一次回流,就是在頁面第一次加載的時候。

重繪和重排的關系:在回流的時候,瀏覽器會使渲染樹中受到影響的部分失效,並重新構造這部分渲染樹,完成回流后,瀏覽器會重新繪制受影響的部分到屏幕中,該過程稱為重繪。

          所以,重排必定會引發重繪,但重繪不一定會引發重排。

   觸發重排的條件:任何頁面布局和幾何屬性的改變都會觸發重排,比如:

  1、頁面渲染初始化;(無法避免)

  2、添加或刪除可見的DOM元素;

  3、元素位置的改變,或者使用動畫;

  4、元素尺寸的改變——大小,外邊距,邊框;

  5、瀏覽器窗口尺寸的變化(resize事件發生時);

  6、填充內容的改變,比如文本的改變或圖片大小改變而引起的計算值寬度和高度的改變;

  7、讀取某些元素屬性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) )

重繪重排的代價:耗時,導致瀏覽器卡慢。

優化:  

1、瀏覽器自己的優化:瀏覽器會維護1個隊列,把所有會引起回流、重繪的操作放入這個隊列,等隊列中的操作到了一定的數量或者到了一定的時間間隔,瀏覽器就會flush隊列,進行一個批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。

2、我們要注意的優化:我們要減少重繪和重排就是要減少對渲染樹的操作,則我們可以合並多次的DOM和樣式的修改。並減少對style樣式的請求。

(1)直接改變元素的className

(2)display:none;先設置元素為display:none;然后進行頁面布局等操作;設置完成后將元素設置為display:block;這樣的話就只引發兩次重繪和重排;

(3)不要經常訪問瀏覽器的flush隊列屬性;如果一定要訪問,可以利用緩存。將訪問的值存儲起來,接下來使用就不會再引發回流;

(4)使用cloneNode(true or false) 和 replaceChild 技術,引發一次回流和重繪;

(5)將需要多次重排的元素,position屬性設為absolute或fixed,元素脫離了文檔流,它的變化不會影響到其他元素;

(6)如果需要創建多個DOM節點,可以使用DocumentFragment創建完后一次性的加入document;

 

var fragment = document.createDocumentFragment(); var li = document.createElement('li'); li.innerHTML = 'apple'; fragment.appendChild(li); var li = document.createElement('li'); li.innerHTML = 'watermelon'; fragment.appendChild(li); document.getElementById('fruit').appendChild(fragment);

(7)盡量不要使用table布局。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM