js性能——DOM编程

hi~第三篇啦
这一篇简短的文章简单说明了在DOM编程过程可以优化的一些点

下面有一些概念需要大家一起认识一下;

DOM遍历

减少对DOM的遍历。

选择器API

querySelectorAll()的原生DOM方法比使用js与DOM遍历要快

重绘重排

浏览器下载完页面的所有组件——html标记、js、css、图片——之后会解析并生成两个内部数据结构:

DOM树
表示页面结构

渲染树
表示DOM节点如何显示

当DOM的变化影响了元素的几何属性,浏览器就需要重新计算元素的几何属性,同样其他元素的几何属性也会因此受到影响。浏览器会使渲染树种受到影响的部分失效,并重新构建渲染树。这个过程称为“重排”

完成重排后,浏览器会重新绘制受影响的部分到屏幕中,称为“重绘”

但是!!
并不是所有的DOM变化都会影响到几何属性(宽和高之类),比如改变颜色。这个时候只会发生重绘,不会重排。

All in all,重绘重排是代价很昂贵的操作,所以尽可能减少发生。

所以,怎样会有重排的发生呢?

重排发生情况

  • 添加或删除可见的DOM元素
  • 元素位置改变
  • 元素尺寸改变
  • 内容改变
  • 页面渲染器初始化
  • 浏览器窗口尺寸改变

渲染树变化的排队与刷新

大多数浏览器通过队列化修改并批量执行来优化重排过程。然而,或许我们会不知不觉的强制刷新队列并要求计划任务立刻执行。

获取布局信息的操作会导致队列刷新,eg:

  • offsetTop,offsetLeft,offsetwidth,offsetHeight
  • scrollTop,scrollLeft,scrollwidth,scrollHeight
  • clientTop,clientLeft,clientwidth,clientHeight
  • getComputedStyle()

以上属性和方法需要返回最新的布局信息,所以浏览器不得不执行渲染队列中的“待处理变化”并重返重排以返回正确的值。

最小化重绘和重排

下面举个例子说明如何减少重绘重排

1
2
3
var e = document.getElementById('mydiv');
e.style.borderLeft = '1px';
e.style.padding = '5px';

上面三个样式属性被改变,每次都会影响元素几何结构,最糟糕的情况下,会导致浏览器触发三次重排。现在大部分现代浏览器为此做了优化,只触发一次重排,但是在旧版浏览器中,或者有一个分离的异步处理过程时,效率还是很低,如果在上面代码执行时,有其他代码请求布局,将会导致三次重排。
可以改为如下

1
e.style.cssText += ";border-left:1px;"

批量修改DOM

通过一些改善来减少重绘与重排的次数:

  • 使元素脱离文档流
  • 对其应用多重改变
  • 把元素带回文档中

通过三种方法来使DOM脱离文档:

  • 隐藏元素,应用修改,重新显示
  • 使用文档片段在当前DOM之外构建一个子树,再把它拷贝会文档
  • 将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换原始元素

让元素脱离动画流

用展开/折叠的方式来显示和隐藏部分页面是一种常见的交互模式。它通常包括产开区域的几何 动画,并将页面其他部分推向下方。

如果程序需要重新计算的节点越多,重排产生的卡顿感也会越明显。

那么应该如何解决呢?下面的步骤可以解决问题

  1. 使用绝对定位页面上面的动画,脱离文档流
  2. 让元素动起来,当他扩大时,会覆盖部分页面。但这只是页面的一个小区域的重绘过程,不会产生重排并重绘页面的大部分内容
  3. 动画结束的时候,恢复定位,从而只会计算一次。

IE与:hover

从IE7开始,IE允许在任何元素(严格模式下)使用:hover这个CSS伪选择器。然而,如果你有大量元素使用了:hover,那么会降低响应速度,IE8更明显

事件委托

事件委托,通俗来说,就是解决页面中大量元素都需要绑定事件处理器从而影响的性能的办法。
它基于:事件逐层冒泡并能被父级元素捕获。

只需要给外层元素绑定一个处理器,就可以处理在其子元素上出发的事件

参考资料

  1. 高性能javascript

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×