DOM優化

1.節點修改

使用cloneNode在外部更新節點然后再通過replace與原始節點互換。

window.onload = function () {
        var orij = document.getElementById('content');
        //新的內容替換原有的內容
        var clone = orij.cloneNode(false);
        //在原有內容的基礎上進行修改
        //var clone = orij.cloneNode(true);
        var list = ['foo','bar','baz'];
        var content;
        for(var i = 0; i < list.length; i++){
            content = document.createTextNode(list[i]);
            clone.appendChild(content);
        }
        orij.parentNode.replaceChild(clone,orij);
    }

2.節點的添加

多個節點插入操作,即使在外面設置節點的元素和風格再插入,由于多個節點還是會引發多次reflow。
優化的方法是創建DocumentFragment,在其中插入節點后再添加到頁面。

 var btn = document.getElementById('btn');
        btn.onclick = function () {
            var list = document.getElementById('list');
            var fragment = document.createDocumentFragment();
            for(var i = 0; i < 5 ; i ++){
                var li = document.createElement('li');
                li.textContent = i;
                fragment.appendChild(li)
            }
            list.appendChild(fragment);
        }

3.CSS樣式轉換

如果需要動態更改CSS樣式,盡量采用觸發reflow次數較少的方式。
可以通過直接設置元素的className直接設置,只會觸發一次reflow。

//css
.content{
            width:200px;;
            height:200px;
            background-color: aqua;
        }
        .container{
            background-color: pink;
            width:200px;
            height: 200px;
        }

//HTML
<div class="content" id="content"></div>

//js
document.getElementById('content').className = "container";

4.減少DOM元素數量

在控制臺的console中輸入下面的語句查看DOM元素數量:

document.getElementsByTagName( '*' ).length

正常頁面的DOM元素數量一般不應該超過1000。
DOM元素過多會使DOM元素查詢效率,樣式表匹配效率降低,是頁面性能最主要的瓶頸之一。

5.DOM操作

  • DOM操作性能問題主要有以下原因:

    • DOM元素過多導致元素定位緩慢。
    • 大量的DOM接口調用。
    • Javascript和DOM之間的交互需要通過函數API接口來完成,造成延時,尤其是在循環語句中。
    • DOM操作觸發頻繁的reflow(layout)和repaint。
    • layout發生在repaint之前,所以layout相對來說會造成更多性能損耗。
      • reflow(layout)就是計算頁面元素的幾何信息。
      • repaint就是繪制頁面元素。
    • 對DOM進行操作會導致瀏覽器執行回流reflow。
  • 解決方法:

    • 純JAVASCRIPT執行時間是很短的。
    • 最小化DOM訪問次數,盡可能在js端執行。
    • 如果需要多次訪問某個DOM節點,請使用局部變量存儲對它的引用。
    • 謹慎處理HTML集合(HTML集合實時連系底層文檔),把集合的長 度緩存到一個變量中,并在迭代中使用它,如果需要經常操作集合,建議把它拷貝到一個數組中。
    • 如果可能的話,使用速度更快的API,比如querySelectorAll和firstElementChild。
    • 要留意重繪和重排。
    • 批量修改樣式時,離線操作DOM樹。
    • 使用緩存,并減少訪問布局的次數。
    • 動畫中使用絕對定位,使用拖放代理。
    • 使用事件委托來減少事件處理器的數量。

事件委托示例

//HTML
<ul id="list">
    <li id="go">go something</li>
    <li id="do">do something</li>
    <li id="sayhi">say hi</li>
</ul>

//JS
var list = document.getElementById('list');
            list.addEventListener('click',function (event) {
                switch(event.target.id){
                    case 'go':
                        alert('aaa');
                        break;
                    case 'do':
                        document.title = 'I change document title';
                        break;
                    case 'sayhi':
                        location.href = 'http://www.lxweimin.com/p/91cb28114c82';
                        break;
                }
            })

5.DOM交互

在JAVASCRIPT中,DOM操作和交互要消耗大量時間,因為它們往往需要重新渲染整個頁面或者某一個部分。

  • 最小化現場更新
    當需要訪問的DOM部分已經被渲染為頁面中的一部分,那么DOM操作和交互的過程就是再進行一次現場更新。

    • 現場更新是需要針對現場(相關顯示頁面的部分結構)立即進行更新,每一個更改(不管是插入單個字符還是移除整個片段),都有一個性能損耗。
    • 現場更新進行的越多,代碼完成執行所花的時間也越長。
  • 多使用innerHTML
    有兩種在頁面上創建DOM節點的方法:

    • 使用諸如createElement()和appendChild()之類的DOM方法。
    • 使用innerHTML。
      • 當使用innerHTML設置為某個值時,后臺會創建一個HTML解釋器,然后使用內部的DOM調用來創建DOM結構,而非基于Javascript的DOM調用。由于內部方法是編譯好的而非解釋執行,故執行的更快。

對于小的DOM更改,兩者效率差不多,但對于大的DOM更改,innerHTML要比標準的DOM方法創建同樣的DOM結構快得多。

6.回流reflow

  • 發生場景。
    • 改變窗體大小。
    • 更改字體。
    • 添加移除stylesheet塊。
    • 內容改變哪怕是輸入框輸入文字。
    • CSS虛類被觸發如 :hover。
    • 更改元素的className。
    • 當對DOM節點執行新增或者刪除操作或內容更改時。
    • 動態設置一個style樣式時(比如element.style.width="10px")。
    • 當獲取一個必須經過計算的尺寸值時,比如訪問offsetWidth、clientHeight或者其他需要經過計算的CSS值。
  • 解決問題的關鍵,就是限制通過DOM操作所引發回流的次數。
    • 在對當前DOM進行操作之前,盡可能多的做一些準備工作,保證N次創建,1次寫入。
    • 在對DOM操作之前,把要操作的元素,先從當前DOM結構中刪除:
      • 通過removeChild()或者replaceChild()實現真正意義上的刪除。
      • 設置該元素的display樣式為“none”。
    • 每次修改元素的style屬性都會觸發回流操作。
      • element.style.backgroundColor = "blue";
      • 使用更改className的方式替換style.xxx=xxx的方式。
      • 使用style.cssText = '';一次寫入樣式。
      • 避免設置過多的行內樣式。
      • 添加的結構外元素盡量設置它們的位置為fixed或absolute。
      • 避免使用表格來布局。
      • 避免在CSS中使用JavaScript expressions(IE only)。
    • 將獲取的DOM數據緩存起來。這種方法,對獲取那些會觸發回流操作的屬性(比如offsetWidth等)尤為重要。
    • 當對HTMLCollection對象進行操作時,應該將訪問的次數盡可能的降至最低,最簡單的,你可以將length屬性緩存在一個本地變量中,這樣就能大幅度的提高循環的效率。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • AJax 優化 緩存 Ajax 請求盡量使用GET, 僅取決于cookie數量 Cookie 優化 減少Cooki...
    KeKeMars閱讀 9,377評論 5 89
  • DOM 一,DOM學習資源 MDN 、DOM specifications 二、學習方法 看別人封裝的代碼 方...
    從前慢pearl閱讀 399評論 0 0
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,805評論 1 92
  • 轉載說明 一、介紹 瀏覽器可以被認為是使用最廣泛的軟件,本文將介紹瀏覽器的工作原理,我們將看到,從你在地址欄輸入g...
    17碎那年閱讀 2,471評論 0 22
  • “這不就是一團亂麻嗎!”“一灘爛泥!”“復制粘貼而已,我也會。”………… 以上對于現代藝術的評價,相信大家都聽過,...
    點融黑幫閱讀 1,027評論 1 14