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屬性緩存在一個本地變量中,這樣就能大幅度的提高循環的效率。