导致 JS 缓慢的三主因之重排重绘

2,847 阅读4分钟

导致 JS 缓慢的三主因之重排重绘

前言

tips:每个技术点都值得优写优学 3 期

tips:Opera 将 repaint 和 reflow 列为导致 JavaScript 缓慢的三个主要因素之一,因此它绝对值得一看,值得一学。

本文先复习重排(reflow)重绘(repaint)的概念,了解完它们之后,再思考在程序设计上,在代码编写上,我们可以做些什么?需要注意些什么?要做的事应该是有利于程序的,起到实际优化作用的。

这或许就是我们学一些概念,或说知识技术点的意义。

重排重会的概念

1.重绘(repaint)

在不改变文档布局的情况下,文档元素发生的例如背景颜色等外观改变的行为可称为重绘。根据 Opera 的说法,重绘的成本也很高,但在处理能力较高的现代设备中,可能感觉不明显。

2.重排(reflow)

reflow 有人翻译为“回流”,也有人翻译为“重构”,也有人翻译为“重排”。我选择翻译为重排,取重新排版布局之意。

那么什么是重排呢?

developers.google 上这样解释:

重排是在网络浏览器中执行的一个流程,用于重新计算文档中各元素的位置和几何形状,以便重新呈现该文档的部分内容或全部内容。

我对重排的理解:

会改变文档布局,会引发元素的位置、尺寸发生改变的行为可称为重排。重排比起重绘,在视觉效果上会更明显,每当操作 DOM 树、更改影响布局的样式、更改元素的 className 属性或更改浏览器窗口大小时,都会发生重排现象。

重排在性能方面的消耗是巨大的,并且是导致 DOM 脚本缓慢的主要原因之一,这在处理能力较低的设备上更为明显。在很多情况下,它们相当于重新布局整个页面,因为元素的重排可能会导致它的祖先元素和子孙元素也发生相应的改变。

现代的电脑设备处理能力普遍较强,所以一些开发者或产品设计者,没有重视应当减少重排的发生,但在一些处理能力不足的特殊终端设备这很重要。

什么时候会发生重排重绘

会引发重排的情况:

  • 浏览器窗口大小的改变,调整窗口大小
  • 删除可见的节点或增加节点
  • 节点尺寸的改变,例如修改元素的width或height等
  • 节点位置的改变,例如使用float或position的改变
  • 节点文本内容的改变,例如不断输入内容。
  • 激活 CSS 伪类,例如 :hover(在 IE 中激活兄弟的伪类)
  • 给元素删除或添加样式表,例如给元素添加一个新的样式,或移除原来的样式。

会引发重绘的情况:

例如元素的 color,background-color 等的改变。

tips:据说重排必定会发生重绘,但重绘未必会发生重排。

此外,个人认为重排重绘的边界并不是没有交集的。所以可能可以把重排重绘绑在一起,认为是一件事,不必仔细区分,而我们更应该付出注意力的是在程序设计时,尽可能降低重排重绘带来的消耗,减少不必要的重排重绘发生。

学完之后

了解了重排重会之后,知道重排重绘可能会产生较大的性能消耗,总结下应该注意的事情。

面对重排重绘的注意事项

  • 减少不必要的 DOM 深度,例如不必要的嵌套结构。在 DOM 树中的一个级别进行更改可能会致使该树的所有级别(上至根节点,下至所修改节点的子级)都随之变化。这会导致花费更多的时间来执行重排。

  • 尽可能减少 CSS 规则的数量,并删除未使用到的 CSS 规则。一些默认就有的 CSS 规则,就不必写了,具有继承性的样式,也不必每级节点都写。calc() 之类的计算方法应该少用。

  • 如果您想进行复杂的渲染更改(例如动画),请在流程外执行此操作。您可以使用 position-absolute 或 position-fixed 来实现此目的。

  • 避免使用不必要且复杂的 CSS 选择器(尤其是后代选择器),因为此类选择器需要耗用更多的 CPU 处理能力来执行选择器匹配。总之不必要的深度,不管是 css 还是 dom 都不是好的选择,这对人和机器都是同样的道理,因为读和理解起来都同样的“费力”。

爬墙翻书查阅了很多资料,但仍感觉不足,持续更新中...