上一次说到了浏览器的渲染过程中,layout的重新布局是导致性能问题的主因,那么什么情况下会导致这一后果,并且有什么好的方式可以优化呢? Let’s go.
术语介绍:
某一个或多个dom节点的变化会影响元素的集合属性【宽&高】,这样会有一部分DOM节点受到影响,此时浏览器会使受到影响的部分失效,并重新构造渲染树,这个过程叫做重排。重排过后,浏览器要重新绘制受影响的部分到屏幕中,这个过程叫做重绘。
正文:
为什么说dom操作是很浪费资源的呢?尽管dom在浏览器中的接口是用JavaScript实现的,但是浏览器通常会把DOM和javaScript独立实现,每次DOM操作都需要他们之间相互访问,也就造成了性能问题,所以要尽量避免这种情况的发生。
上面说的只是访问DOM元素,如果是修改元素,则会导致浏览器重新计算页面的几何变化。
先说一下重绘,重绘之前是不一定有重排这个动作的,比如改变页面的背景颜色,就只会发生一次重绘。顺便也说一下何时发生重排:
- 添加或删除可见的DOM元素
- 元素位置改变
- 元素尺寸改变(边框,宽高)
- 浏览器窗口尺寸改变
如果有一系列的元素等待被更新,比如添加数条列表到正文中,很多浏览器会通过批量执行来优化重排过程。但是这种优化"很不可靠",当访问一些属性的手,会导致强制刷新队列,从而有时无法做到批量。
手动实现批量修改
- 元素脱离文档流
- 对元素应用多重改变
- 把脱离的元素待会文档中
脱离文档流可以使用display
属性。如下所示
var ul = document.getElementById('list')
ul.style.display = 'none';
// operation
ul.style.display = 'block'
这样,就只有在第一步和第三步会发生重排。
还有一种办法是通过fragment
片段,创建一个,然后附加到原始文档中。
var fragment = document.createDocumentFragment();
// operation
document.getElementById('list').appendChild(fragment)
这种方式,只需要触发一次重排,也只访问了一次DOM节点,更推荐使用。
当然了,想优化性能,可以做的更多,比如对访问布局信息进行缓存(本地定义一个变量然后赋值就可以了),因为获取偏移量或者滚动位置时,浏览器为了返回最新值,会刷新当前队列并应用变更,这里不过多讨论。
当然了,现在前端这么发达,可能有的时候不需要我们来考虑这么多事情,下次,让我们一起来探讨一下React中的虚拟DOM。