给页面渲染时间加速 干掉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 相关文章推荐
JavaScript 组件之旅(二)编码实现和算法
Oct 28 Javascript
获取阴历(农历)和当前日期的js代码
Feb 15 Javascript
AngularJS 如何在控制台进行错误调试
Jun 07 Javascript
JS实现刷新父页面不弹出提示框的方法
Jun 22 Javascript
jquery计算出left和top,让一个div水平垂直居中的简单实例
Jul 13 Javascript
Angularjs 制作购物车功能实例代码
Sep 14 Javascript
AngularJS使用自定义指令替代ng-repeat的方法
Sep 17 Javascript
浅谈 vue 中的 watcher
Dec 04 Javascript
vue-cli与webpack处理静态资源的方法及webpack打包的坑
May 15 Javascript
jQuery easyui datagird编辑行删除行功能的实现代码
Sep 20 jQuery
jQuery判断自定义属性data-val用法示例
Jan 07 jQuery
js简单粗暴的发布订阅示例代码
Jan 23 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获取用户IPv4或IPv6地址的代码
2012/11/15 PHP
php实现CSV文件导入和导出
2015/10/24 PHP
特殊字符、常规符号及其代码对照表
2006/06/26 Javascript
JAVASCRIPT车架号识别/验证函数代码 汽车车架号验证程序
2012/01/08 Javascript
jquery $.ajax相关用法分享
2012/03/16 Javascript
JS继承用法实例分析
2015/02/05 Javascript
cocos2dx骨骼动画Armature源码剖析(三)
2015/09/08 Javascript
javascript每日必学之封装
2016/02/23 Javascript
jQuery实现鼠标滑过图片移动特效
2016/12/08 Javascript
那些精彩的JavaScript代码片段
2017/01/12 Javascript
使用canvas进行图像编辑的实例
2017/08/29 Javascript
详解VUE 对element-ui中的ElTableColumn扩展
2018/03/28 Javascript
JavaScript函数定义方法实例详解
2019/03/05 Javascript
基于nodejs的微信JS-SDK简单应用实现
2019/05/21 NodeJs
浅析JS中NEW的实现原理及重写
2020/02/20 Javascript
记一次react前端项目打包优化的方法
2020/03/30 Javascript
基于JS实现计算24点算法代码实例解析
2020/07/23 Javascript
pygame学习笔记(1):矩形、圆型画图实例
2015/04/15 Python
一个基于flask的web应用诞生(1)
2017/04/11 Python
python执行系统命令后获取返回值的几种方式集合
2018/05/12 Python
Python3.6简单的操作Mysql数据库的三个实例
2018/10/17 Python
Python中实现单例模式的n种方式和原理
2018/11/14 Python
pandas去重复行并分类汇总的实现方法
2019/01/29 Python
用Python进行websocket接口测试
2020/10/16 Python
python爬虫如何解决图片验证码
2021/02/14 Python
医学院四年学习生活的自我评价
2013/11/06 职场文书
学习雷锋寄语大全
2014/04/11 职场文书
师德师风个人反思
2014/04/28 职场文书
巾帼志愿者活动方案
2014/08/17 职场文书
领导班子遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
公务员个人考察材料
2014/12/23 职场文书
幼儿园小班个人总结
2015/02/12 职场文书
公司承诺书格式范文
2015/04/28 职场文书
2015年社区教育工作总结
2015/05/13 职场文书
整脏治乱工作简报
2015/07/21 职场文书
MIME类型中application/xml与text/xml的区别介绍
2022/01/18 HTML / CSS