操作dom_传统DOM操作对性能的影响

前言

在浏览器当中,dom的实现和ECMAScript的实现是分离的。

例如,在IE中,ECMAScrit的实现在jscript.dll中,而DOM的实现在mshtml.dll中;在Chrome中使用WebKit中的 WebCore处理DOM和渲染,但ECMAScript是在V8引擎中实现的,其他浏览器的情况类似。

因此,操作dom,就是通过js代码调用dom的接口,就相当于两个相互独立的模块发生了交互。这样,相比于在同一个模块当中互相调用,这种跨模块的调用它的性能损耗是非常高的。

然而,dom操作影响性能最主要是因为它导致了浏览器的重绘(repaint)重排(reflow)

为了可以更加深刻地理解重绘和重排对性能的影响,需要简单了解一下浏览器的渲染原理。

浏览器渲染流程

首先提到页面渲染,最重要的是关键路径渲染:指与当前用户操作有关的内容。例如用户刚刚打开一个页面,首屏的显示就是当前用户操作相关的内容,具体就是浏览器收到 HTML、CSS 和 JavaScript 等资源并对其进行处理从而渲染出 Web 页面。

了解浏览器渲染的过程与原理,很大程度上是为了优化关键渲染路径,但优化应该是针对具体问题的解决方案,所以优化没有一定之规。例如为了保障首屏内容的最快速显示,通常会提到渐进式页面渲染,但是为了渐进式页面渲染,就需要做资源的拆分,那么以什么粒度拆分、要不要拆分,不同页面、不同场景策略不同。具体方案的确定既要考虑体验问题,也要考虑工程问题。

cd1757feee540ef20c50b81af16d75ca.png

如图我们可以看出浏览器渲染大致经历以下过程:

  1. 解析HTML文档,解析HTML,生成DOM树,解析CSS样式,解析CSS,生成CSSOM(css规则树)

  2. 根据生成的DOM和CSSOM构建渲染树(Render Tree)

  3. 根据渲染树计算每个节点在屏幕的位置,尺寸等信息(就是布局排列计算)

  4. 将渲染树绘制到屏幕上。

详细了解一下这里面发生的事情:

  1. 构建DOM树:当浏览器接收到来自服务器响应的HTML文档后,会遍历文档节点,生成DOM树。需要注意的是在DOM树生成的过程中有可能会被CSS和JS的加载执行阻塞,渲染阻塞下面会讲到

  2. 构建CSSOM树:浏览器解析CSS文件并生成CSS规则树

  3. 渲染阻塞:当浏览器遇到一个script标签时,DOM构建将暂停,直到脚本加载执行,然后继续构建DOM树。每次去执行Javascript脚本都会严重阻塞DOM树构建,如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM没有下载和构建,那么浏览器甚至会延迟脚本执行和构建DOM,直到这个CSSOM的下载和构建。所以,script标签引入很重要,实际使用时可以遵循下面两个原则:

         1. css优先:引入顺序上,css资源先于js资源

         2. js后置:js代码放在底部,且js应尽量少影响DOM构建

    还有一个小知识:当解析html时,会把新来的元素插入dom树里,同时去查找css,然后把对应的样式规则应用到元素上,查找样式表是按照从右到左的顺序匹配的例如:div p {...},会先寻找所有p标签并判断它的父标签是否为div之后才决定要不要采用这个样式渲染。所以平时写css尽量用css或者id,不要过度层叠

  4. 构建渲染树:通过DOM树和CSS规则我们可以构建渲染树。浏览器会从DOM树根节点开始遍历每个可见节点(注意是可见节点)对每个可见节点,找到其适配的CSS规则并应用。渲染树构建完后,每个节点都是可见节点并且都含有其内容和对应的规则的样式。这也是渲染树和DOM树最大的区别所在。渲染是用于显示,那些不可见的元素就不会在这棵树出现了。除此以外,display none的元素也不会被显示在这棵树里。visibility hidden的元素会出现在这棵树里。

  5. 渲染布局:布局阶段会从渲染树的根节点开始遍历,然后确定每个节点对象在页面上的确切大小与位置,布局阶段的输出是一个盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小。

  6. 渲染树绘制:在绘制阶段,遍历渲染树,调用渲染器的paint()方法在屏幕上显示其内容。渲染树的绘制工作是由浏览器的UI后端组件完成的。

传统DOM结构操作方式对性能的影响很大,原因是频繁操作DOM结构操作会引起页面的重排(reflow)和重绘(repaint),浏览器不得不频繁地计算布局,重新排列和绘制页面元素,导致浏览器产生巨大的性能开销。

重排:浏览器第一次渲染页面布局后,后续引起页面各个元素节点在页面所处位置的重新计算与重新布局的行为都叫做重排。元素的位置或尺寸发生了改变,浏览器需要重新计算渲染树,导致渲染树的一部分或全部发生变化。渲染树重新建立后,浏览器会重新绘制页面上受影响的元素。也就是说,重排,改变的是dom文档的结构,例如dom元素的位置或者尺寸发生了变化,需要重新布局,就会发生重排。

引起重排的操作

  • offsetTop,offsetLeft,offsetWidth,offsetHeight, scrollTop/Left/Width/Height、clientTop/Left/Width/Height。

  • 只要涉及页面元素布局位置等信息发生的改变,都会触发重排(元素尺寸改变、边距填充、边框宽高度)

  • style,input,resize等。

  • 这里补充一个局部重排:一个DOM宽高之类几何信息定死,然后在DOM内部重排就只重新渲染DOM内部,不影响外界。

重绘布局计算完成后,页面会重新绘制,这时浏览器会遍历渲染树,使用UI后端层绘制每个节点。当元素外观发生变化但没有改变布局,重新把元素绘制的过程。

传统DOM的属性操作几乎可以说是家常便饭,当然也有不少对应的优化方式,比如说绝对定位,模板引擎一次渲染,缓存HTML字符串,将dom操作积累起来作批量操作或合并多次的DOM操作为单次的DOM操作等,但是稍不留神还是会引发浏览器重排和重绘,加上传统的DOM操作代码较为繁杂,使项目代码维护起来难度大,成本高,促使使用者中的佼佼者们对DOM操作进行了新思考。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值