頁面迴流與重繪的那點事兒

頁面渲染過程

在這裏插入圖片描述

  1. 瀏覽器把HTML代碼解析成一顆DOM Tree,每個元素標籤都是DOM Tree中的一個節點,根節點是Document
  2. 在形成DOM Tree後,從DOM Tree根節點開始,遍歷每一個可見的節點,並找到合適的、匹配的CSSOM規則,應用在節點上;
  3. DOM TreeCSSOM Tree連接在一起形成Render Tree
  4. 最終繪製出頁面,顯示在屏幕上

什麼叫回流與重繪?

  • 頁面迴流:當render tree中的一部分(或全部)因爲元素的規模尺寸、佈局、隱藏等改變而引起的頁面重新渲染(或者叫作重新構建繪製);
  • 頁面重繪:當render tree中的一些元素需要更新屬性,但這些屬性只會影響元素的外觀、風格,而不會影響元素的佈局,此類的頁面渲染叫作頁面重繪。

在網頁生成的時候,至少會渲染一次。用戶訪問的過程中,任何對Render Tree節點的操作都會引起重新渲染。
需要注意的是頁面重繪不一定會引起迴流,但迴流一定會引起頁面重繪。

常見的迴流與重繪操作

  1. DOM節點的添加、刪除;
  2. 調整窗口大小(resize事件);
  3. 元素位置改變、元素尺寸改變(width/height/padding/border/margin);
  4. CSS僞類的激活(如hover);
  5. 對樣式的操作(不同屬性有不同的影響)
  6. 元素樣式屬性的讀取操作

不同樣式的操作造成迴流、重繪影響

開發過程中,提高性能的技巧

頁面的迴流、重繪在項目中是不可避免的,但過高、頻繁的迴流、重繪必定導致網頁性能低下,影響客戶體驗感。所以,在開發過程中,我們應儘可能的避免迴流、重繪,儘量少觸發頁面的重新渲染。

1. 儘量不要把讀操作和寫操作,放在一個語句裏面。
// 下列操作只會造成一次迴流、重繪
div.style.color = 'blue';
div.style.marginTop = '30px';

// 下列操作造成兩次的迴流、重繪
div.style.color = 'blue';
var margin = parseInt(div.style.marginTop);
div.style.marginTop = (margin + 10) + 'px';

在樣式的寫操作之後,有對元素進行offsetscrollclientgetComputedStyle()屬性讀取操作,都會觸發瀏覽器立即重新渲染。

// 壞的寫法 --> 讀寫操作放同一個語句
div.style.left = div.offsetLeft + 10 + "px";

// 好的寫法
var left = div.offsetLeft;
div.style.left = left + 10 + 'px';
2. 不要一條條地修改樣式,而是通過改變classcssText屬性,一次性修改樣式。
// 壞的寫法
div.style.left = '10px';
div.style.top  = '10px';

// 好的寫法
div.className += 'newClassName';

div.style.cssText += 'background-color:red;font-size:20px;';
3. 儘可能使用Document Fragment對象或者cloneNode(),在克隆的節點上進行操作,然後再用克隆的節點替換原始節點。
// 壞的寫法
for( var i = 0; i<2; i++ ){
    var li = document.createElement('li');
    li.textContent = i;
    ul.appendChild(li);
}

// 好的寫法
var fragment = document.createDocumentFragment();
for( var i = 0; i<2; i++ ){
    var li = document.createElement('li');
    li.textContent = i;
    fragment.appendChild(li);
}
ul.appendChild(fragment);
4. 先將元素設置爲display:none,再對元素進行操作,最後恢復顯示,這樣只需要兩次的重新渲染。
5. 儘可能地使用position;,而不是float來進行元素浮動。因爲使用position屬性不用考慮它對其他元素的影響,迴流的開銷會比較小。
6. 儘可能地將display屬性設爲可見,不可見屬性的元素不會影響迴流和重繪 (visibility的元素只對重繪有影響,不影響迴流)。
7. 使用虛擬DOM的腳本庫,比如ReactVue等。
8. 使用window.requestAnimationFrame()window.requestIdleCallback()這兩個方法調節重新渲染。

注意:window.requestAnimationFrame()只能在IE10及以上使用,而window.requestIdleCallback()在IE上是不支持的。這兩個方法在阮一峯阮一峯的博客上有詳細的介紹。

參考鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章