在使用DOM操作时,同样的效果用不同的方式来实现,性能方面也会有很大的差异。尤其在移动式设备上,资源本来就很有限,一旦DOM写不好的话操作就会非常卡顿。这个周末,就写个DOM性能小记吧。错漏之处,望多指教。

  1、浅说reflow

  首先讲讲最近我才了解到的一个比较深入且模糊的东西——reflow

  从字面上理解的话,reflow有回流、重排的意思。它是指在DOM内容更新或增删时发生的一个响应过程,可以理解为页面内容改变了,然后发生重新排版这样的一个行为。我们可以将执行DOM操作细分为以下三个过程:读取HTML内容——>页面reflow——>展示更新内容。

  由于reflow是一个重整布局和样式的过程,相当消耗性能。所以我们优化DOM性能实际上就是避免执行更多DOM操作,即减少reflow过程

  2、减少reflow常用方法

  【1】采用临时变量存储,一次性操作DOM

    以我笔记本为例,分别测试了以下两段代码:

 //代码1
window.onload = function(){
var oUl = document.getElementById('ul1');
for (var i = 0; i < 10000; i++) {
oUl.innerHTML +=i;
}
}
//代码2
window.onload = function(){
var oUl = document.getElementById('ul1');
var str = '';
for (var i = 0; i < 10000; i++) {
str +=i;
}
oUl.innerHTML = str;
}

  在chrome浏览器下用时取样如下,前五次为两段代码分别运行,后五次为放一起先后执行时间:

t/ms 1 2 3 4 5 6 7 8 9 10
代码1 9067.696 8900.826 9114.520 8987.592 9220.753 9344.496 8783.459 8797.731 9337.738 8835.503
代码2 4.100 1.883 2.177 2.262 2.416 5.464 2.053 1.891 2.053 1.975

                                                            

  从上面数据明显看得出,同样执行10000次拼接,代码二远快于代码一。

  不难得出结论:减少DOM访问,改用外部变量临时存储内容,最后再一步执行DOM操作的效率远高于分次执行DOM操作。

  代码二的速度约是代码一的4000倍,可粗略计算出,innerHTML每查找并赋值一次,用时就接近1ms。

 【2】采用class修改多个样式,一次性更改属性

    分别测试以下代码:

 //代码三
window.onload = function(){
var oUl = document.getElementById('ul1');
for (var i = 0; i < 20000; i++) {
if(i%2==0){
oUl.style.fontSize = "18px";
oUl.style.lineHeight = "30px";
oUl.style.padding = "20px";
oUl.style.width = "100px";
oUl.style.height = "100px";
}else{
oUl.style.fontSize = "16px";
oUl.style.lineHeight = "40px";
oUl.style.padding = "30px";
oUl.style.width = "200px";
oUl.style.height = "200px";
}
}
} //代码四
window.onload = function(){
var oUl = document.getElementById('ul1');
for (var i = 0; i < 20000; i++) {
if(i%2==0){
oUl.className = "class1";
}else{
oUl.className = "class2";
}
}
}

  同样在chrome浏览器下测试执行用时如下,前五次为两段代码分开运行,后五次为两段代码放一起运行(排除电脑不同时间点运行的差异):

t/ms 1 2 3 4 5 6 7 8 9 10
代码3 346.540 471.160 322.437 327.363 335.818 283.553 346.819 318.261 313.144 333.789
代码4 38.666 20.042 19.550 26.465 27.294 38.429 33.793 37.031 34.928 36.221

                                        

  从上面的数据可以看出,通过设置class改变多个样式的方法比分次改变样式明显快得多。

  在不考虑js代码赋值运算增多带来了误差的情况下(实际上很小),代码4的方法平均耗时也比代码3的方法快10多倍。因为在代码3中,我每改变一个样式都会产生一次reflow,即reflow了5次。而在代码四中使用className却只reflow了一次,但一次reflow改变了多个样式

  这里需要注意的是,不是所有样式的改变都会产生reflow的。只有会影响布局的样式才会,例如width,height,display,line-height,margin,padding,font,background等等。诸如color,opacity,visibility等则不会,因为它们只会产生repaint。你可以想象得到,改变颜色、透明度等值对页面的结构是不会产生任何影响的。这里我就不展开讲了。

【3】采用变量存储节点属性值,减少获取次数

  测试代码:

 //代码5
for (var i = 0; i < 10000; i++) {
if(i%2==0){
document.getElementById('ul1').style.left = document.getElementById('ul1').offsetHeight + 10 + "px";
}else{
document.getElementById('ul1').style.left = document.getElementById('ul1').offsetHeight - 10 + "px";
}
} //代码6
var u1 = document.getElementById('ul1');
var uW = u1.offsetHeight;
for (var i = 0; i < 10000; i++) {
if(i%2==0){
u1.style.left = uW + 10 + "px";
}else{
u1.style.left = uW - 10 + "px";
}
}

   分别执行以上代码10000次的10个时间样本对比:  

t/ms 1 2 3 4 5 6 7 8 9 10
代码5 1256.209 1175.189 1384.690 1241.207 1223.094 1371.524 1186.556 1176.889 1269.450 1215.922
代码6 20.633 14.353 17.901 19.665 31.405 20.503 24.451 18.909 23.883 14.472

  同样可以看出,代码6是明显比代码5运行速度快的。

  当我们知道某一个节点的某些属性值是确定时,这时候我们可以将这个值保存在变量中,而不需要每次重新获取。否则当运行次数达到一定量后,会严重影响程序执行的速度。因为当第一次使用变量获取某个节点的值时,页面就会只reflow一次,并把这个值保存在内存中。下次程序需要时从内存中取就可以了。而代码5中则每次都沿着document去读取这些值,这些值虽然没有改变,但这些值是浏览器需要计算才能获得的,所以每次都会reflow一次。

  会导致reflow的属性有offsetLeft/Top、offsetHeight/Width、scrollTop/Left/Width/Height、clientTop/Left/Width/Height等。

  养成使用这种方法的习惯,不但能提高程序性能,有时候还可以节省代码量,使程序更简洁。

  

  说明:原创文章,转载时请注明出处,谢谢。

DOM性能小记的更多相关文章

  1. 浅谈DOM性能考虑

    浅谈DOM性能考虑 很多人都会忽视脚本对Web应用整体性能的影响.为保证应用的流畅运行,在为文档编写和应用脚本时,需要注意一些问题.一.尽量减少访问DOM和尽量减少标记    访问DOM的方式对脚本性 ...

  2. 【react-router】从Link组件和a标签的区别说起,react-router如何实现导航并优化DOM性能?

    (注:参考自官方英文文档V3.X版本) react-router是伴随着react框架出现的路由系统,它也是公认的一种优秀的路由解决方案.在使用react-router时候,我们常常会使用其自带的路径 ...

  3. web前端优化--DOM性能优化

    1.DOM访问与修改的优化: DOM访问是有代价的,修改DOM则会引起DOM的重绘与重排,而这两种操作会消耗性能. (1)缓存DOM:将频繁访问的对象或属性使用变量缓存起来,每次访问的时候,直接使用变 ...

  4. Javascript之DOM性能优化

    原文地址:http://ce.sysu.edu.cn/hope/Item/140355.aspx 作者:陈古松 来源:本站原创 发布时间:2015-03-14 更新时间:2015-03-14  点击数 ...

  5. Dom基础(二):Dom性能优化

    一.尽量将DOM查询做缓存 1 let pElements = document.getElementById('div1') //将dom缓存 2 3 for(let i=0:i<pEleme ...

  6. 深入剖析虚拟DOM提升性能(Vue,React);

    I.原始渲染方式(直接操作DOM): 1.state数据: 2.JSX模板: 3.数据 + 模板 相结合,生成真实的DOM来显示: 4.state发生改变: 5.数据 + 模板结合,生成真实的DOM来 ...

  7. 《高性能javascript》 领悟随笔之-------DOM编程篇(二)

    <高性能javascript> 领悟随笔之-------DOM编程篇二 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...

  8. 为什么DOM操作很慢

    转自:http://kb.cnblogs.com/page/534571/ 一直都听说DOM很慢,要尽量少的去操作DOM,于是就想进一步去探究下为什么大家都会这样说,在网上学习了一些资料,这边整理出来 ...

  9. DOM的相关优化

    为什么要进行DOM优化? DOM对象本身也是一个js对象,所以严格来说,并不是操作这个对象慢,而是说操作了这个对象后,会触发一些浏览器行为,比如布局(layout)和绘制(paint). 首先先说一些 ...

随机推荐

  1. linq join多字段

    from VS in m2db.Inf_VehicleSale join RS1 in m2db.His_RecSale on new { VS.vehicleCode, auctionCode=VS ...

  2. HttpListenerCS客户端监听http

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. Go语言获取项目当前路径

    package main import ( "fmt" "os" "os/exec" "strings" ) func ...

  4. HIVE: Transform应用实例

    数据文件内容 steven:100;steven:90;steven:99^567^22 ray:90;ray:98^456^30 Tom:81^222^33 期望最终放到数据库的数据格式如下: st ...

  5. SNF开发平台WinForm之二-开发-单表表单管理页面-SNF快速开发平台3.3-Spring.Net.Framework

    2.1运行效果: 2.2开发实现: 2.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...

  6. NGUI 基础知识

    UIRoot 管理 scalePixelPerfect : 像素匹配,图片不会被缩放,除非屏幕高度小于 Minimum Height 或者大于 maximum  Height,如果那样的话,就使用 F ...

  7. nodejs+express中设置登录拦截器

    在nodejs+express中,采用nodejs后端路由控制用户登录后,为了加强前端的安全性控制,阻止用户通过在浏览器地址栏中输入地址访问后台接口,在app.js中需要加入拦截器进行拦截: /*** ...

  8. MMM和MHA的对比和应用(PPT分享)

    分享主题:MySQL高可用架构 --- MMM&MHA在大众点评应用和改进 内容简介:本次演讲,主要讲述以下几个方面 1. MMM在点评网是如何使用的 2. 细数MMM上踩过的坑以及如何填坑 ...

  9. 3、使用Oracle Logminer同步Demo

    使用Oracle Logminer同步Demo 1 Demo介绍 1.1 Demo设想 前面介绍了Oracle LogMiner配置使用以及使用LogMiner进行解析日志文件性能,在这篇文章中将利用 ...

  10. es6新特性学习

    本文用来记录一下es6的新特性,持续更新.... es6在前端目前还不能大面试使用,包括移动端兼容也不好.不过在node中已可以使用其中96%的特性.也可使用一些插件将es6转化为es5,比如babl ...