使用javascript封裝的一個datagrid控件時,可能會提出這個問題,在datagrid里面顯示1000條數(shù)據(jù),而且需要綁定其click,hover,dblclick事件。(可能你會覺得這個需求有點無聊。為什么要顯示1000行數(shù)據(jù),可以分頁的。我最開始也這么想,但是分頁有些問題解決不了,比如,我們需要選中多條數(shù)據(jù)做一個操作,可能我要選的記錄在第一頁,第n頁。這樣還需要記錄行選中狀態(tài)。而且可能在分頁查詢的時候數(shù)據(jù)已經(jīng)發(fā)生了更改。比如當你翻頁到第二頁的時候,第一頁選中的數(shù)據(jù)已經(jīng)刪除了。這樣選中的數(shù)據(jù)已經(jīng)是“臟數(shù)據(jù)”了。)
javascript執(zhí)行很慢的時候瀏覽器會提示腳本執(zhí)行過慢甚至假死(還是要鄙視一下IE6執(zhí)行js的速度)。但是上面的問題很有可能就會出現(xiàn)瀏覽器奔潰的情況。所以在實現(xiàn)這個功能,不得不審視一下現(xiàn)在的實現(xiàn)。
看看下面的jQuery代碼,類似于現(xiàn)有的寫法:
$(function(){
var arr = [];
var date1 =(new Date()).getTime();
for (var i=0;i<1000 ; i++){
arr.push("<tr><td>"+(new Date())+"</td><td>"+(new Date())+"</td><td>"+(new Date())+"</td><td>"+(new Date())+"</td><td>"+(new Date())+"</td></tr>");
}
var $rows= $(arr.join("")).appendTo("#tablebody");
var date2 =(new Date()).getTime();
//date2-date1 =453ms
//事件處理 406ms
$rows.click(function(){
$("#tablebody .highlight").removeClass("highlight");
this.className="highlight";
}).hover(function(){
this.className="hover";
},function(){
this.className="";
}).dblclick(function(){
alert("dblclick");
});
var date3 =(new Date()).getTime();
alert((date2-date1)+"\n"+(date3-date2));
});
這段代碼在table中新增1000行,然后把監(jiān)聽每行的click,hover,dblclick事件。這個代碼在IE8上執(zhí)行時間是0.95s左右(具體時間因環(huán)境而異)。0.95的時間去顯示數(shù)據(jù)確實是讓人難以接受。這個時間可能是后臺數(shù)據(jù)庫查詢的時間。這個時間其實還有優(yōu)化的空間。
第一部分的DOM操作已經(jīng)是比較快的了。這個時間會跟cell中顯示的內(nèi)容直接相關(guān),能夠的做的性能優(yōu)化貌似都做了。jQuery中的appendTo在DOM操作性能上應(yīng)該難以超越了。令我驚訝的是,綁定事件的時間竟然會有406ms。與DOM操作時間同一個量級。我用了幾種方法做了對比:
//第一種情況:復(fù)雜的事件處理 406ms
$rows.click(function(){
$("#tablebody .highlight").removeClass("highlight");
this.className="highlight";
}).hover(function(){
this.className="hover";
},function(){
this.className="";
}).dblclick(function(){
alert("dblclick");
});
//第二種情況:簡單事件處理 141ms
$rows.click(function(){
alert("clicked");
}).dblclick(function(){
alert("dblclick");
});
//第三種情況:使用原生的javascript事件綁定 62ms
var rows= document.getElementById("tablebody").getElementsByTagName("tr");
for (var i=0;i<rows.length ; i++){
(function (row){
row.onclick= function(){
alert("clicked");
};
row.ondblclick= function(){
alert("dblclicked");
};
})(rows[i]);
}
//第四種情況:只是用jquery做選擇器 47ms
$rows.each(function(){
this.onclick= function(){
alert("clicked");
};
this.ondblclick= function(){
alert("dblclicked");
};
});
第一種情況與第二種情況的對比可以發(fā)現(xiàn)事件綁定的越少,時間越短。
第二種情況與第三種情況的對比可以發(fā)現(xiàn)使用原生的javascript事件綁定會比jQuery時間短。這個貌似有點不好解釋,jQuery封裝的目的可能更在于減少代碼量。jQuery的事件綁定比原生的事件綁定會有這么大的差別也是讓我驚訝的。
第三種情況其實多做了一次DOM選擇,因為$rows其實就是新增行jQuery對象。所以直接用each方法遍歷綁定事件,時間是最短的。
總的來說,性能問題不僅僅在于我們理解的DOM操作上面,事件的綁定其實也是很關(guān)乎性能的。大家平時是怎么解決這種問題了,歡迎交流。
上面的代碼下載