頻繁地對於DOM進行操做的非常損耗性能,但在富網頁應用中咱們編寫腳本無可避免地要跟DOM打交道,到底怎麼才能優化這個性能瓶頸呢,大體從如下三種狀況去考慮: html
訪問和修改DOM元素chrome
修改DOM樣式,會形成頁面的重繪和從新排版數組
經過DOM事件處理程序來響應用戶瀏覽器
訪問和修改DOM元素app
在瀏覽器中,DOM的實現和Javascript的實現一般是保持相互獨立的。下面瞭解一下主流瀏覽器的渲染引擎和JS引擎:ide
瀏覽器 | 渲染引擎(內核) | JS引擎 |
---|---|---|
IE | mshtml.dll(Trident) | JScript |
Chrome | WebCore(WebKit) | V8 |
FireFox | Gecko | Spider-Monkey/TraceMonkey |
Safari | WebCore(WebKit) | JavaScriptCore/SquirrelFish |
訪問DOM元素的代價就是交一次「橋費」,修改DOM元素則會致使瀏覽器從新計算頁面的幾何變化。若是是循環修改DOM元素,其代價可想而知。以下代碼:函數
function innerHTMLLoop1(){
for(var count=0;count<10000;count++){
document.getElementById("test").innerHTML +="增長內容";
}
}
在這段代碼中,每循環一次都要對DOM元素訪問兩次:一次是讀取innerHTML屬性的內容,另外一次是把新的內容寫入它。因此一個優化的辦法就是使用一個局部變量存儲更新後的內容,在循環結束時再一次性寫入:oop
function innerHTMLLoop2(){
var content ="";
for(var count=0;count<10000;count++){
content +="增長內容";
}
document.getElementById("test").innerHTML += content ;
}
更新頁面的兩種方法性能比較:innerHTML和DOM方法(如document.creatElment)。性能差異不大,innerHTML好一些,使用簡單嘛。另外還有一個更新頁面的方法是節點克隆--element.cloneNode()。性能
HTML集合的操做優化
HTML集合是用於存放DOM節點引用的類數組對象。可經過下列的方法或屬性獲得這樣的集合:
document.getElementsByName()HTML集合會實時查詢文檔信息,也就是說當你要用到這個集合時,它會自動查詢文檔的最新信息。請看以下代碼:
var allDivs = document.getElementsByTagName("div");
for(var i=0;i<allDivs.length;i++){
document.body.appendChild(document.createElement("div"));
}
例如像上面的那段代碼實際上是個死循環,由於每一次訪問div集合的length屬性,它都會從新計算文檔中的div元素數目。這就是html集合低效率的來源。要改進代碼就用一個局部變量保存div集合的length屬性:
for(var i=0, len=allDivs.length; i<len; i++){...}
var len = 集合.length;
//HTML集合轉換成數組
function toArray(coll){
for(var a=[], i=0, len=coll.legnth; i<len; i++){
a[i] = coll[i];
}
return a;
}
//使用
var coll = document.getElementsByTagName("div");
var divs = toArray(coll);
有人可能會問,這樣多用了一個數組副本到底值不值得?這個卻是要看狀況吧。不過另一種選擇,使用局部變量:
function loopColletion(){
var coll = document.getElmentsByTagName("div");
var len = coll.length;
var el = null;
for(var i = 0; i<len; i++){
el = coll[i];
//而後訪問局部變量el
}
}
許多瀏覽器提供了API函數返回元素節點,這些API都是原生的,因此可用的話就儘可能用。下圖列舉了一些DOM的屬性:
上圖列舉的全部屬性能被FF,safari,chrome,opera所支持,ie6-8只支持children。
遍歷children比childNodes更快,由於集合項少了。HTML源碼中的空格其實是文本節點,但他們不包含在children中。
另外還有兩個比較好的選擇器API:document.querySelectorAll()和document.querySelector()。前者接收一個CSS選擇器字符串參數並返回一個NodeList類數組對象而不是返回HTML集合,後者只返回符合查詢條件的第一個節點。很遺憾IE六、7不支持這兩個API。