给页面渲染时间加速 干掉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调用WebService的实现代码
Jun 19 Javascript
php和js对数据库图片进行等比缩放示例
Apr 28 Javascript
使用GruntJS构建Web程序之构建篇
Jun 04 Javascript
JS+CSS实现实用的单击输入框弹出选择框的方法
Feb 28 Javascript
js表单登陆验证示例
Oct 19 Javascript
js仿QQ邮箱收件人选择与搜索功能
Feb 10 Javascript
详解vue嵌套路由-query传递参数
May 23 Javascript
Js利用prototype自定义数组方法示例
Oct 20 Javascript
详解webpack3编译兼容IE8的正确姿势
Dec 21 Javascript
vue-cli 使用axios的操作方法及整合axios的多种方法
Sep 12 Javascript
手把手教你实现 Promise的使用方法
Sep 02 Javascript
javascript代码实现简易计算器
Jan 25 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开发不能违背的安全规则 过滤用户输入
2011/05/01 PHP
php urlencode()与urldecode()函数字符编码原理详解
2011/12/06 PHP
PHP实现绘制3D扇形统计图及图片缩放实例
2014/10/01 PHP
php返回json数据函数实例
2014/10/09 PHP
php中 ob_start等函数截取标准输出的方法
2015/06/22 PHP
PHP 获取ip地址代码汇总
2015/07/05 PHP
juqery 学习之五 文档处理 包裹、替换、删除、复制
2011/02/11 Javascript
jQuery效果 slideToggle() 方法(在隐藏和显示之间切换)
2011/06/28 Javascript
读jQuery之十三 添加事件和删除事件的核心方法
2011/08/23 Javascript
通过js动态操作table(新增,删除相关列信息)
2012/05/23 Javascript
jQuery中$.click()无效问题分析
2015/01/29 Javascript
基于javascript实现根据身份证号码识别性别和年龄
2016/01/22 Javascript
js对象浅拷贝和深拷贝详解
2016/09/05 Javascript
完美解决node.js中使用https请求报CERT_UNTRUSTED的问题
2017/01/08 Javascript
JavaScript中动态向表格添加数据
2017/01/24 Javascript
JS关于刷新页面的相关总结
2018/05/09 Javascript
React 无状态组件(Stateless Component) 与高阶组件
2018/08/14 Javascript
微信小程序实现类似微信点击语音播放效果
2020/03/30 Javascript
JavaScript图片旋转效果实现方法详解
2020/06/28 Javascript
vue中el-input绑定键盘按键(按键修饰符)
2020/07/22 Javascript
Vue 禁用浏览器的前进后退操作
2020/09/04 Javascript
pyqt4教程之messagebox使用示例分享
2014/03/07 Python
使用Python构建Hopfield网络的教程
2015/04/14 Python
python实现闹钟定时播放音乐功能
2018/01/25 Python
基于python操作ES实例详解
2019/11/16 Python
iframe跨域的几种常用方法
2019/11/11 HTML / CSS
仓库理货员岗位职责
2013/12/18 职场文书
体现团队精神的口号
2014/06/06 职场文书
专题民主生活会对照检查材料思想汇报
2014/09/29 职场文书
怎样写家长意见
2015/06/04 职场文书
对公司的意见和建议
2015/06/04 职场文书
2019关于实习生工作安排及待遇的管理方案!
2019/07/16 职场文书
php字符串倒叙
2021/04/01 PHP
基于Python的EasyGUI学习实践
2021/05/07 Python
Java后台生成图片的完整步骤
2021/08/04 Java/Android
sqlserver连接错误之SQL评估期已过的问题解决
2022/03/23 SQL Server