前端性能优化(二)通过一个实例聊聊DOM操作优化

DOM操作优化现在已经不是很受重视了,原因是有了virtual DOM,外加上浏览器自身的优化也越来越到位。

多年前我曾经做过一个表格,这个表格对性能要求非常高,踩过一些坑,不断优化,最后得到了比较好的结果。

一般来说表格用于展示数据,一次性渲染,数据是不会变的,而且还做了分页,如果这样那么无论怎么做都不会出大问题的。如果加一个条件呢,?每一个单元格每秒更新6次,屏幕可视区域有30条,怎么办?对,这是展示股票行情的实际需要。

该怎么做?当时年少不懂事,直接拿table写了一下,结果就是性能烂的不行,cpu跑满了,及其卡,卡到没法响应用户操作,甚至浏览器直接死掉了。究其原因就是使用js更新数据的时候会触发reflow,而且table会触发更多的reflow,我们一直在说js操作DOM慢,慢的原因也在于操作DOM会引发reflow。

那么都哪些情况会触发reflow呢?如下

  1. 对DOM树做修改(插入、移动、删除)。
  2. 修改网页中的内容,在contenteditable的元素中输入内容。
  3. DOM动画。
  4. 测量DOM尺寸,如offsetHeight、getComputedStyle等。
  5. 更新通过style更新DOM样式。
  6. 修改DOM class。
  7. 添加删除样式表。
  8. 调整浏览器窗口大小。
  9. 网页滚动。

想这样一个问题,一个小块区域reflow和整个页面reflow哪个花费的时间短?显然是小块区域。所以方向就定了,减少reflow次数和reflow影响的范围。比如可以这样做

  1. 用空间换时间,测量DOM获取的值能缓存就缓存。
  2. 样式更新用批量而不是一个style一个style的更新。
  3. DOM更新用批量的方式。
  4. 将表格的每一个单元格的position设置为absolute,absolute会脱离文档流,这样reflow会限定到absolute范围内。
  5. 其他任何减少refllow的操作。

最后优化的结果还是特别满意的,虽然更新频繁,但是用户操作很流畅,cpu也很低。

另外还做了虚拟滚动,每一行都是absolute的,所以知道是第几行就知道它应该在哪里。理论上只有在可视区域的数据才需要渲染到DOM树,当滚动时销毁不在可视区域的数据,将需要在可视区域的数据渲染出来。当然debounce处理一定是必要的。为了滚动平滑前后各多渲染半屏。

关于为啥要做虚拟滚动可以这样来解释,你有50万条数据,每条50列,你一次渲染出来会怎样?首先渲染那么多DOM到页面上内存是否能抗住?渲染需要花多长时间?等等很多问题。做了虚拟滚动资源的消耗就相对可控了。

不足之处欢迎补充和讨论。

推荐文章