使用javascript封装的一个datagrid控件时,可能会提出这个问题,在datagrid里面显示1000条数据,而且需要绑定其click,hover,dblclick事件。(可能你会觉得这个需求有点无聊。为什么要显示1000行数据,可以分页的。我最开始也这么想,但是分页有些问题解决不了,比如,我们需要选中多条数据做一个操作,可能我要选的记录在第一页,第n页。这样还需要记录行选中状态。而且可能在分页查询的时候数据已经发生了更改。比如当你翻页到第二页的时候,第一页选中的数据已经删除了。这样选中的数据已经是“脏数据”了。)
javascript执行很慢的时候浏览器会提示脚本执行过慢甚至假死(还是要鄙视一下IE6执行js的速度)。但是上面的问题很有可能就会出现浏览器奔溃的情况。所以在实现这个功能,不得不审视一下现在的实现。
看看下面的jQuery代码,类似于现有的写法:
$(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行,然后把监听每行的click,hover,dblclick事件。这个代码在IE8上执行时间是0.95s左右(具体时间因环境而异)。0.95的时间去显示数据确实是让人难以接受。这个时间可能是后台数据库查询的时间。这个时间其实还有优化的空间。
第一部分的DOM操作已经是比较快的了。这个时间会跟cell中显示的内容直接相关,能够的做的性能优化貌似都做了。jQuery中的appendTo在DOM操作性能上应该难以超越了。令我惊讶的是,绑定事件的时间竟然会有406ms。与DOM操作时间同一个量级。我用了几种方法做了对比:
//第一种情况:复杂的事件处理 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");
};
});
第一种情况与第二种情况的对比可以发现事件绑定的越少,时间越短。
第二种情况与第三种情况的对比可以发现使用原生的javascript事件绑定会比jQuery时间短。这个貌似有点不好解释,jQuery封装的目的可能更在于减少代码量。jQuery的事件绑定比原生的事件绑定会有这么大的差别也是让我惊讶的。
第三种情况其实多做了一次DOM选择,因为$rows其实就是新增行jQuery对象。所以直接用each方法遍历绑定事件,时间是最短的。
总的来说,性能问题不仅仅在于我们理解的DOM操作上面,事件的绑定其实也是很关乎性能的。大家平时是怎么解决这种问题了,欢迎交流。
上面的代码下载