给页面加速,干掉Dom Level 0 Event
现在的web应用越来越复杂,需要响应各种各样的用户触发事件,因而也就不可避免的,需要给我们的html页面上的dom元素增加事件监听函数。
我们知道给dom元素绑定事件监听函数的方法有如下3种:
1. 页面html:
<button onclick=”test();”></button>
2. 页面html:
<button id=”btn”></button>
Javascript:
document.getElementById(“btn”).onclick = test;
3. 页面html:
<button id=”btn”></button>
Javascript:
document.getElementById(“btn”).atachEvent(“onclick”,test); //ie
这3种方法的功能效果和差异,大家都了解,在此就不在赘述了。但是这3种方法,对页面渲染的速度,资源的消耗,却是有很大不同的。
正文后面的html代码是一个demo页面,大家可以用ie浏览器打开,通过注释不同的代码段,查看页面运行效果。
可以看到第一种方式的效率是最低的,随着页面节点的增多,页面渲染时间急剧增加,在ie7下运行,大概670ms。
第二种方式明显好一些,在ie7下,大概250ms。
而第三种方式则是最快的方法,也是web前端开发推荐的标准写法,在ie7下,大概188ms。
然后我们去掉事件绑定的逻辑,发现只渲染dom元素,不绑定事件的时间,仅仅125ms。可见事件绑定的时间消耗还是很大的,尤其是第一种方式,也就是Dom Level 0 Event,最为耗时。
另外,大家运行各段代码的时候,不妨打开任务管理器,找到浏览器对应的进程,查看代码运行时cpu的消耗以及内存的使用。
我们可以看到,Dom Level 0 Event,对cpu的消耗明显要高很多。
对内存的消耗分析:
重新打开浏览器,空白页面的内存占用量大概是37M,虚拟内存为28M,页面渲染后:
1. 内存使用 54M,虚拟内存41M;
2. 内存使用44M,虚拟内存31M;
3. 内存使用44M,虚拟内存31M。
可见Dom Level 0 Event对内存的消耗,也远远超出了其它方式。
为什么Dom Level 0 Event会这么消耗系统资源呢?对cpu和内存的消耗都远远超出了其它方式,我们来做一个简单分析。
为了便于分析,我们不妨修改一下我们的代码 <button onclick=”debugger;test();”></button> ,然后运行页面,在ie的script debugger里我们找到堆栈调用这一项,可以看到有一个anonymos function,这个function是从何而来的呢?原来浏览器在对Dom Level 0 Event做绑定的时候,会自动生成一个包含我们的代码的匿名函数,然后把这个匿名函数绑定到事件,类似于如下方式:
document.getElementById(“btn”).onclick = function(event){
test();
} ;
而ie浏览器又没有足够的智能,区分出众多内部功能完全一致的匿名函数,并合并它们的引用,所以导致了随着dom事件绑定的越来越多,匿名函数的个数也越来越多。因为要声明数量众多的事件处理匿名函数,也就不难明白,为什么会消耗如此多的系统资源了。
随着dom元素的增多,这个资源消耗就会越来越严重。而且我们可以尝试着刷新一下页面,发现随着刷新的次数增加,页面运行越来越慢,cpu消耗也越来越多,内存也会有少量增加。可见,Dom Level 0 Event 还会带来少量的内存泄露,至于时间的延长,cpu消耗的加剧,推测是因为浏览器忙于释放众多的匿名函数所占用的资源所带来的后果。
进一步深入,由于ie浏览器是基于冒泡的事件模型,子元素的event会冒泡到父元素,所以更极致的优化是去掉众多子元素的事件绑定,而将事件绑定到父元素。在正文后的demo中,也有这方面的尝试,可以看到不仅cpu,内存消耗最低,时间上也跟渲染干净的html页面是一样的。
所以,我们在页面事件绑定中,要尽量避免Dom Level 0 Event,而且要尽可能的将事件上升(当然也要考虑事件处理的灵活性)。
demo:
<BODY>
<ul id="list"></ul>
<SCRIPT LANGUAGE="JavaScript">
<!--
var $ = function(id){
return document.getElementById(id)
};
function test(){
alert(1)
}
var ul = $("list");
var count = 5000;
// ie7
//-->
</SCRIPT>
<script>
var d = new Date()
var str = [];
for(var i = 0;i<count;i++){
str.push('<li onclick="test();">'+i+'</li>')
}
ul.innerHTML = str.join("");
alert(new Date - d);
//670 刷新时时间增加 85
</script>
<SCRIPT LANGUAGE="JavaScript">
<!--
/*var d = new Date()
var str = [];
for(var i = 0;i<count;i++){
str.push('<li>'+i+'</li>')
}
ul.innerHTML = str.join("");
alert(new Date - d); */
//125
//-->
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
<!--
/*var d = new Date()
var str = [];
for(var i = 0;i<count;i++){
str.push('<li>'+i+'</li>')
}
ul.innerHTML = str.join("");
var li = document.getElementsByTagName("li");
var l = li.length;
for(var i=0;i<l;i++){
li[i].onclick = test;
}
li = null;
alert(new Date - d);*/
//250
//-->
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
<!--
/*var d = new Date()
var str = [];
for(var i = 0;i<count;i++){
str.push('<li>'+i+'</li>')
}
ul.innerHTML = str.join("");
var li = document.getElementsByTagName("li");
var l = li.length;
for(var i=0;i<l;i++){
li[i].attachEvent("onclick",test);
}
li = null;
alert(new Date - d);*/
//188
//-->
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
<!--
/*var d = new Date()
var str = [];
for(var i = 0;i<count;i++){
str.push('<li>'+i+'</li>')
}
ul.innerHTML = str.join("");
ul.attachEvent("onclick",test);
alert(new Date - d);*/
//125
//-->
</SCRIPT>
</BODY>