为什么要减少dom操作

本文摘自:  [https://my.oschina.net/u/1580821/blog/744684] ,在这里做一下笔记

DOM其实就是一个javascript对象,每个DOM节点就是这个对象里面的属性。所以,操作DOM其实就是修改js对象的属性值(就好比:js.a = “b”),这个js对象改变后,会触发一些浏览器的行为,这个行为(比如layout和paint)就是代价大、耗性能的罪魁祸首了。

首先,从浏览器层面入手,有渲染引擎和js引擎 渲染引擎工作:

  • 解析HTML代码,生产DOM tree
  • 解析CSS样式,结合DOM tree生产Render tree(display: none;的结点不会存在Render tree上,最后不会被paint)
  • 计算Render tree各个节点的布局信息,比如box的位置、尺寸、颜色、外形等
  • 根据计算后的布局信息,调用浏览器的UI引擎进行渲染。

layout(布局)和paint(绘制)是代价最大的,layout就是布局变动造成重新计算(耗CPU,有时也很耗内存),paint就是调用浏览器UI引擎进行渲染展示页面(耗CPU和内存)。paint设计到另一个引擎的细节,暂不讨论(先当成是java中用awt绘制panel一样耗性能耗资源吧)。下面详细说下layout如何耗性能耗资源:

layout(布局),主要是计算文档中元素的位置、大小等信息,是渲染工作的第三步。

在HTML被加载时会进行layout,样式改变会导致layout,js执行的时候涉及到布局信息都会导致layout,估计这时候快疯了,那么多样式,每个样式、每个js都layout一次,岂不是一个页面要layout几百万次。。。哈哈,别担心,浏览器还是精明的,对于layout行为是lazy的,不会傻到每个样式进行一次layout,对于CSS和JS都会把需要layout行为的数据缓存到一个队列中,当上下文完成执行后进行一次layout(css比如:结点的样式描述完。js比如:一个代码块执行完)。

浏览器的lazy会带来另外一个问题,layout信息在队列中的时候,我需要获取DOM节点信息就获取不到了,这时候浏览器就会提前执行一次layout,这就是DOM操作耗性能耗资源的罪魁祸首。

导致提前layout的常见情况(通过chrome浏览器自带的控制台可以看到):

1、通过js获取DOM属性

2、增/删/DOM节点

3、改变浏览器窗口大小

4、改变字体

5、激活css伪类

6、修改DOM的属性,涉及到大小、位置等(该颜色不会激活提前的layout)

7、其他js操作。。。

还有,特别重要的。。。动画的每一帧都会导致layout,为了减少动画带来的layout性能损失,可以动画元素绝对定位,使其脱离文本流。另外,requestAnimationsFrame也可以把layout积累后进行。另外,HTMLCollection对象最好缓存,否则layout次数将乘以数组的长度系数,还有就是减少DOM元素的嵌套深度,并优化CSS的深度。

根据性能测试(呵呵,别人测的,我没测过)显示,假设DOM元素为5千(业内好像都以这个为临界点),减少DOM操作,可以大大减少客户端的性能消耗,假如是手机端更为明显,如DOM操作太频繁,手机端会因内存爆满或CPU占用过度而出现浏览器闪退现象。

在实际开发中测试如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="test1"></div>
<div id="test2"></div>
<script>
    window.onload = function () {
        console.time("test1");
        var test1= document.getElementById("test1");
        for (var i = 0; i < 10000; i++) {
            test1.innerHTML += "dom"
        }
        console.timeEnd("test1");
        console.time("test2");
        var test2= document.getElementById("test2");
        for (var i = 0, str = ""; i < 10000; i++) {
            str += "dom"
        }
        test2.innerHTML = str;
        console.timeEnd("test2");
    }
</script>
</body>
</html>


将上述代码运行,log时间为:

test1: 1667.266845703125ms

test2: 1.238037109375ms

可以看到减少dom的操作可以节省多少时间!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值