页面性能优化


引起页面重新渲染的方法,避免在循环中使用:
// Firefox 只要读取 offsetHeight 属性就会发生重排(reflow),chrome 需要设置值才会发生。
clientHeight, clientLeft, clientTop, clientWidth, focus(), getBoundingClientRect(), getComputedStyle(), getClientRects(), innerText, offsetHeight, offsetLeft, offsetParent, offsetTop, offsetWidth, outerText, scrollByLines(), scrollByPages(), scrollHeight, scrollIntoView(), scrollIntoViewIfNeeded(), scrollLeft, scrollTop, scrollWidth

回流一定会触发重绘,而重绘不一定会回流

将耗时操作放在空闲时间去做:requestAnimationFrame,setTimeout

layout thrashing 会导致动画在开始的时候卡顿,垃圾回收的触发会导致动画运行过程中让动画卡住,不使用 RAF 则会导致动画帧率低。

适当调用GPU,如 css translate, will-change: transform;

contain: strict; // 指定隔离程度,是有副作用的,strict 是 layout, style and paint 的组合,告诉浏览器永远不会产生回流。如屏幕之外的内容可以设置为 paint,即告诉浏览器不需要重绘。
content-visibility: auto; 相当于自动调整 contain 值。 // 虚拟滚动
// 可访问,但是里面通过 css 隐藏的也具备可访问性,添加 dom 属性防止

以下三种情况,会导致网页重新渲染:
  • 修改 DOM
  • 修改样式表
  • 用户事件(比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)
重新渲染,就需要重新生成布局和重新绘制。前者叫做"重排"(reflow),后者叫做"重绘"(repaint)。

浏览器已经很智能了,会尽量把所有的变动集中在一起,排成一个队列,然后一次性执行。但中间有让页面重新渲染的方法(上述)会引发浏览器立即重新渲染。(每当你在读取前一次修改的样式时都会强制执行了同步重排. via:MDN)
  • 样式表越简单,重排和重绘就越快。
  • 重排和重绘的 DOM 元素层级越高,成本就越高。
  • table 元素的重排和重绘成本,要高于div元素
样式是通过重排得到的,那么最好缓存结果

不要一条条地改变样式,而要通过改变 class,或者 cssText 属性,一次性地改变样式。

尽量使用离线 DOM,而不是真实的网页 DOM,如 cloneNode,Document Fragment

先将元素设为 display: none(需要1次重排和重绘)
行内样式会触发一次额外的回流(重排)事件,
在解析 table 布局时需要计算大量的单元格的尺寸,使用table-layout:fixed(固定表格布局,不根据内容自动计算宽度,默认所有列等宽)可以缓解部分性能消耗
visibility : hidden 的元素只对重绘有影响,不影响重排

使用虚拟 DOM 的脚本库减少对 DOM 的操作,比如 React 等

使用 requestAnimationFrame()、requestIdleCallback() 这两个方法调节重新渲染
requestAnimationFrame() 方法。它可以将某些代码放到下一次重新渲染时执行。
// requestVideoFrameCallback: 便于处理视频,回调函数的参数还有视频帧的元数据信息

window.requestIdleCallback() 指定只有当一帧的末尾有空闲时间,才会执行回调函数(传递给回调函数一个有timeRemaining方法【返回剩余时间】,didTimeout【是否超时调用】属性的deadline对象)。它还可以接受第二个参数,表示指定的毫秒数。如果在指定的这段时间之内,每一帧都没有空闲时间,那么函数fn将会强制执行。

isInputPending 主动检查用户代理是否需要处理用户输入,如果有则中断执行让用户代理去处理用户输入 // includeContinuous: true 来检测连续事件;在宏任务中恢复