重排重绘与帧优化管理
浏览器渲染网页的过程
- 首先渲染引擎将 HTML 解析成 DOM 树;
- 再将 CSS 代码解析成 CSSOM(CSS Object Model);
- 结合 DOM 和 CSSOM 生成渲染树。通过 CSSOM 中的 class,id 等属性将对应的样式挂载到 DOM Tree 上。(即对每个节点描述视觉信息);
- 根据渲染树生成页面布局。即将渲染树的视觉信息进行平面合成; - layout
- 将布局绘制到屏幕上。- paint
重排和重绘
网页生成,至少需要渲染一次。用户访问的过程中,还会不断的重新渲染。
由于浏览器采用流式布局模型(Flow Based Layout),对渲染树布局计算通常只需要遍历一次就能完成。但对于 table 及其内部的子元素,可能需要多次计算,这是为什么要避免使用 table 布局的主要原因。
重新渲染就是重新生成布局和重新绘制
以下行为都会导致重新渲染
- 修改 dom(增、删、改 dom 节点)
- 修改样式表
- 用户事件(比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等)
- 重排 当节点的几何尺寸发生变化,布局需要重新计算时,也就触发了重排。
- 重绘 相反,如果节点只是样式发生改变,则触发重绘
重绘不一定会触发重排,重排必然会导致重绘。
减少重排和重绘,优化性能
频繁的重排和重绘,以及部分的重排是导致页面性能低下的主要原因。那么减少重排、重绘及合理的重排至关重要。
如果修改某个深层的节点,它并不会对其他节点造成影响。但修改一个页面顶级或嵌套多层节点的节点时,会影响整个页面的改变,付出的性能代价也是巨大的。
浏览器有一个比较只能的策略,基于你的脚本会创建一个变化队列,浏览器不断向队列添加变更的节点状态,然后一次执行,尽量减少重新渲染。
但是你的脚本也会让浏览器立即执行重新渲染,一般来说样式的写操作之后,如果有下面的这些读操作,会立即引起浏览器的重新渲染:
1 | offsetTop/offsetLeft/offsetWidth/offsetHeight |
所以从性能角度考虑,尽量不要吧读操作和写操作放在一个语句里
1 | // bad |
帧管理
网页动画的每一帧都是一次重新渲染,一般网页动画,需要达到每秒30-60帧才能比较顺畅。如果要达到动画最佳的流畅状态,每次重新渲染的时间不能超过16.66ms。