1.節(jié)點(diǎn)修改
使用cloneNode在外部更新節(jié)點(diǎn)然后再通過(guò)replace與原始節(jié)點(diǎn)互換卸奉。
window.onload = function () {
var orij = document.getElementById('content');
//新的內(nèi)容替換原有的內(nèi)容
var clone = orij.cloneNode(false);
//在原有內(nèi)容的基礎(chǔ)上進(jìn)行修改
//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.節(jié)點(diǎn)的添加
多個(gè)節(jié)點(diǎn)插入操作钝诚,即使在外面設(shè)置節(jié)點(diǎn)的元素和風(fēng)格再插入,由于多個(gè)節(jié)點(diǎn)還是會(huì)引發(fā)多次reflow择卦。
優(yōu)化的方法是創(chuàng)建DocumentFragment敲长,在其中插入節(jié)點(diǎn)后再添加到頁(yè)面。
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樣式轉(zhuǎn)換
如果需要?jiǎng)討B(tài)更改CSS樣式秉继,盡量采用觸發(fā)reflow次數(shù)較少的方式祈噪。
可以通過(guò)直接設(shè)置元素的className直接設(shè)置,只會(huì)觸發(fā)一次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元素?cái)?shù)量
在控制臺(tái)的console中輸入下面的語(yǔ)句查看DOM元素?cái)?shù)量:
document.getElementsByTagName( '*' ).length
正常頁(yè)面的DOM元素?cái)?shù)量一般不應(yīng)該超過(guò)1000辑鲤。
DOM元素過(guò)多會(huì)使DOM元素查詢效率,樣式表匹配效率降低杠茬,是頁(yè)面性能最主要的瓶頸之一月褥。
5.DOM操作
-
DOM操作性能問(wèn)題主要有以下原因:
- DOM元素過(guò)多導(dǎo)致元素定位緩慢弛随。
- 大量的DOM接口調(diào)用。
- Javascript和DOM之間的交互需要通過(guò)函數(shù)API接口來(lái)完成宁赤,造成延時(shí)舀透,尤其是在循環(huán)語(yǔ)句中。
- DOM操作觸發(fā)頻繁的reflow(layout)和repaint决左。
- layout發(fā)生在repaint之前愕够,所以layout相對(duì)來(lái)說(shuō)會(huì)造成更多性能損耗。
- reflow(layout)就是計(jì)算頁(yè)面元素的幾何信息佛猛。
- repaint就是繪制頁(yè)面元素惑芭。
- 對(duì)DOM進(jìn)行操作會(huì)導(dǎo)致瀏覽器執(zhí)行回流reflow。
-
解決方法:
- 純JAVASCRIPT執(zhí)行時(shí)間是很短的继找。
- 最小化DOM訪問(wèn)次數(shù)遂跟,盡可能在js端執(zhí)行。
- 如果需要多次訪問(wèn)某個(gè)DOM節(jié)點(diǎn)婴渡,請(qǐng)使用局部變量存儲(chǔ)對(duì)它的引用幻锁。
- 謹(jǐn)慎處理HTML集合(HTML集合實(shí)時(shí)連系底層文檔),把集合的長(zhǎng) 度緩存到一個(gè)變量中边臼,并在迭代中使用它越败,如果需要經(jīng)常操作集合,建議把它拷貝到一個(gè)數(shù)組中硼瓣。
- 如果可能的話,使用速度更快的API置谦,比如querySelectorAll和firstElementChild堂鲤。
- 要留意重繪和重排。
- 批量修改樣式時(shí)媒峡,離線操作DOM樹瘟栖。
- 使用緩存,并減少訪問(wèn)布局的次數(shù)谅阿。
- 動(dòng)畫中使用絕對(duì)定位半哟,使用拖放代理。
- 使用事件委托來(lái)減少事件處理器的數(shù)量签餐。
事件委托示例
//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.reibang.com/p/91cb28114c82';
break;
}
})
5.DOM交互
在JAVASCRIPT中寓涨,DOM操作和交互要消耗大量時(shí)間,因?yàn)樗鼈兺枰匦落秩菊麄€(gè)頁(yè)面或者某一個(gè)部分氯檐。
-
最小化現(xiàn)場(chǎng)更新
當(dāng)需要訪問(wèn)的DOM部分已經(jīng)被渲染為頁(yè)面中的一部分戒良,那么DOM操作和交互的過(guò)程就是再進(jìn)行一次現(xiàn)場(chǎng)更新。- 現(xiàn)場(chǎng)更新是需要針對(duì)現(xiàn)場(chǎng)(相關(guān)顯示頁(yè)面的部分結(jié)構(gòu))立即進(jìn)行更新冠摄,每一個(gè)更改(不管是插入單個(gè)字符還是移除整個(gè)片段)糯崎,都有一個(gè)性能損耗几缭。
- 現(xiàn)場(chǎng)更新進(jìn)行的越多,代碼完成執(zhí)行所花的時(shí)間也越長(zhǎng)沃呢。
-
多使用innerHTML
有兩種在頁(yè)面上創(chuàng)建DOM節(jié)點(diǎn)的方法:- 使用諸如createElement()和appendChild()之類的DOM方法年栓。
- 使用innerHTML。
- 當(dāng)使用innerHTML設(shè)置為某個(gè)值時(shí)薄霜,后臺(tái)會(huì)創(chuàng)建一個(gè)HTML解釋器某抓,然后使用內(nèi)部的DOM調(diào)用來(lái)創(chuàng)建DOM結(jié)構(gòu),而非基于Javascript的DOM調(diào)用黄锤。由于內(nèi)部方法是編譯好的而非解釋執(zhí)行搪缨,故執(zhí)行的更快。
對(duì)于小的DOM更改鸵熟,兩者效率差不多副编,但對(duì)于大的DOM更改,innerHTML要比標(biāo)準(zhǔn)的DOM方法創(chuàng)建同樣的DOM結(jié)構(gòu)快得多流强。
6.回流reflow
- 發(fā)生場(chǎng)景痹届。
- 改變窗體大小。
- 更改字體打月。
- 添加移除stylesheet塊队腐。
- 內(nèi)容改變哪怕是輸入框輸入文字。
- CSS虛類被觸發(fā)如 :hover奏篙。
- 更改元素的className柴淘。
- 當(dāng)對(duì)DOM節(jié)點(diǎn)執(zhí)行新增或者刪除操作或內(nèi)容更改時(shí)。
- 動(dòng)態(tài)設(shè)置一個(gè)style樣式時(shí)(比如element.style.width="10px")秘通。
- 當(dāng)獲取一個(gè)必須經(jīng)過(guò)計(jì)算的尺寸值時(shí)为严,比如訪問(wèn)offsetWidth、clientHeight或者其他需要經(jīng)過(guò)計(jì)算的CSS值肺稀。
- 解決問(wèn)題的關(guān)鍵第股,就是限制通過(guò)DOM操作所引發(fā)回流的次數(shù)。
- 在對(duì)當(dāng)前DOM進(jìn)行操作之前话原,盡可能多的做一些準(zhǔn)備工作夕吻,保證N次創(chuàng)建,1次寫入繁仁。
- 在對(duì)DOM操作之前涉馅,把要操作的元素,先從當(dāng)前DOM結(jié)構(gòu)中刪除:
- 通過(guò)removeChild()或者replaceChild()實(shí)現(xiàn)真正意義上的刪除黄虱。
- 設(shè)置該元素的display樣式為“none”控漠。
- 每次修改元素的style屬性都會(huì)觸發(fā)回流操作。
- element.style.backgroundColor = "blue";
- 使用更改className的方式替換style.xxx=xxx的方式。
- 使用style.cssText = '';一次寫入樣式盐捷。
- 避免設(shè)置過(guò)多的行內(nèi)樣式偶翅。
- 添加的結(jié)構(gòu)外元素盡量設(shè)置它們的位置為fixed或absolute。
- 避免使用表格來(lái)布局碉渡。
- 避免在CSS中使用JavaScript expressions(IE only)聚谁。
- 將獲取的DOM數(shù)據(jù)緩存起來(lái)。這種方法滞诺,對(duì)獲取那些會(huì)觸發(fā)回流操作的屬性(比如offsetWidth等)尤為重要形导。
- 當(dāng)對(duì)HTMLCollection對(duì)象進(jìn)行操作時(shí),應(yīng)該將訪問(wèn)的次數(shù)盡可能的降至最低习霹,最簡(jiǎn)單的朵耕,你可以將length屬性緩存在一個(gè)本地變量中,這樣就能大幅度的提高循環(huán)的效率淋叶。