给页面渲染时间加速 干掉Dom Level 0 Event


Posted in Javascript onDecember 19, 2012

现在的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>
Javascript 相关文章推荐
jquery validator 插件增加日期比较方法
Feb 21 Javascript
javascript限制用户只能输汉字中文的方法
Nov 20 Javascript
JavaScript给url网址进行encode编码的方法
Mar 18 Javascript
浅谈Javascript数组的使用
Jul 29 Javascript
js+css实现select的美化效果
Mar 24 Javascript
node.js express安装及示例网站搭建方法(分享)
Aug 22 Javascript
javascript简单链式调用案例分析
May 10 Javascript
vue项目中vue-i18n和element-ui国际化开发实现过程
Apr 25 Javascript
Vue使用NPM方式搭建项目
Oct 25 Javascript
mpvue微信小程序多列选择器用法之省份城市选择的实现
Mar 07 Javascript
vue中使用vee-validator完成表单校验方案
Nov 01 Javascript
Element Rate 评分的使用方法
Jul 27 Javascript
img onload事件绑定各浏览器均可执行
Dec 19 #Javascript
JavaScript实现快速排序(自已编写)
Dec 19 #Javascript
js 使用form表单select类实现级联菜单效果
Dec 19 #Javascript
JS限制上传图片大小不使用控件在本地实现
Dec 19 #Javascript
JS上传图片前的限制包括(jpg jpg gif及大小高宽)等
Dec 19 #Javascript
js限制文本框输入长度两种限制方式(长度、字节数)
Dec 19 #Javascript
ajax java 实现自动完成功能
Dec 19 #Javascript
You might like
解析php DOMElement 操作xml 文档的实现代码
2013/05/10 PHP
深入解析php之sphinx
2013/05/15 PHP
Windows下Apache + PHP SESSION丢失的解决过程全纪录
2015/04/07 PHP
[原创]PHP实现逐行删除文件右侧空格的方法
2015/12/25 PHP
PHP的PDO操作简单示例
2016/03/30 PHP
解决laravel(5.5)访问public报错的问题
2019/10/12 PHP
PHP实现一个按钮点击上传多个图片操作示例
2020/01/23 PHP
Jquery 高亮显示文本中重要的关键字
2009/12/24 Javascript
JQuery扩展插件Validate 2通过参数设置验证规则
2011/09/05 Javascript
JS简单计算器实例
2015/01/20 Javascript
AngularJS模板加载用法详解
2016/11/04 Javascript
Websocket协议详解及简单实例代码
2016/12/12 Javascript
详谈Angular 2+ 的表单(一)之模板驱动型表单
2017/04/25 Javascript
微信小程序中吸底按钮适配iPhone X方案
2017/11/29 Javascript
原生JS使用Canvas实现拖拽式绘图功能
2019/06/05 Javascript
nodejs制作小爬虫功能示例
2020/02/24 NodeJs
SpringBoot+Vue 前后端合并部署的配置方法
2020/12/30 Vue.js
[01:31](回顾)杀出重围,决战TI之巅
2014/07/01 DOTA
Python中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
2014/10/23 Python
python中is与双等于号“==”的区别示例详解
2017/11/21 Python
Python+selenium实现截图图片并保存截取的图片
2018/01/05 Python
python遍历文件夹,指定遍历深度与忽略目录的方法
2018/07/11 Python
Django模板标签中url使用详解(url跳转到指定页面)
2020/03/19 Python
Django的ListView超详细用法(含分页paginate)
2020/05/21 Python
浅析Python的命名空间与作用域
2020/11/25 Python
selenium+超级鹰实现模拟登录12306
2021/01/24 Python
优秀学生事迹材料
2014/02/08 职场文书
厂区绿化方案
2014/05/08 职场文书
应届大专生自荐书
2014/06/16 职场文书
环保志愿者活动总结
2014/06/27 职场文书
公司给客户的感谢信
2015/01/23 职场文书
2015年专项整治工作总结
2015/04/03 职场文书
硕士学位申请报告
2015/05/15 职场文书
2016新年致辞
2015/08/01 职场文书
《从现在开始》教学反思
2016/02/16 职场文书
golang的文件创建及读写操作
2022/04/14 Golang