第一个遇到的api是 requestAnimationFrame ,那么就来认识并记录一下吧。
requestAnimationFrame(简称 RAF)
RAF 告诉浏览器:“我想执行一个动画,请在下一次重绘前调用我的回调函数。” 浏览器会将回调中的 DOM 操作集中在一次重绘中执行,避免卡顿。
在下一次重绘前 ,集中在一次重绘中执行 这些是什么意思?RAF和浏览器在作什么交易?
要看懂这句话,要知道requestAnimationFrame 既不是由 TypeScript(TS) 也不是由 CommonJS 提供的,它是 浏览器环境 原生提供的 Web API ,用于更高效地实现动画等与页面渲染同步的操作。更要搞明白浏览器渲染流程 和 回流(重排)、重绘 的概念。
浏览器渲染流程
来个简化版本的浏览器渲染流程浅尝一下:
- 构建 DOM 树:解析 HTML 标签,生成节点树。
- 构建 CSSOM 树:解析 CSS 样式,生成样式规则树。
- 合成渲染树:结合 DOM 树和 CSSOM 树,标记出哪些节点需要显示、以及它们的样式。
- 布局(回流 / 重排):计算渲染树中节点的几何位置(宽高、坐标等)。
- 绘制(重绘):根据布局结果,把节点的样式绘制到屏幕上(颜色、阴影等视觉效果)。
回流(重排)** 和 重绘
在这个简化版本的浏览器渲染流程中,可以看到回流(重排) 和 重绘 。那么它们具体是干些啥?先简单理解一下。
- 回流(重排):发生在 “布局” 阶段,影响节点的位置和大小。
- 重绘:发生在 “绘制” 阶段,只影响节点的视觉样式(不改变布局)。
触发回流的操作(影响布局):
修改几何属性:width、height、padding、margin、left、top、border 等。
修改结构:增删 DOM 节点(如 appendChild、removeChild),或修改 display 属性(如从 none 改为 block)。
修改字体相关属性:font-size、font-weight 等(字体变化会影响文本布局)。
浏览器事件:窗口 resize、滚动(scroll)、获取某些布局信息(如 offsetWidth、scrollTop)。
触发重绘的操作(不影响布局):
修改外观属性:color、background、border-color、box-shadow、opacity、visibility(仅隐藏不脱离文档流)等。
修改渐变、阴影等装饰效果:不影响节点位置和大小,只改变视觉呈现。
“集中在一次重绘中执行” 的含义
1)合并 DOM 操作,减少回流 / 重绘次数
假设你在 RAF 回调里做了多个 DOM 操作(比如同时改元素的 left、opacity、background),浏览器会把这些操作 “攒” 到一起,只触发一次回流(如果涉及布局变化) + 一次重绘,而不是每个操作都单独触发。
对比传统定时器(setTimeout):
- 用
setTimeout时,多个 DOM 操作可能分散在不同 “帧” 执行,导致多次回流 / 重绘,容易卡顿。 - 用 RAF 时,浏览器会合并操作,减少渲染次数,让动画更流畅。
2)与浏览器刷新率同步
显示器有固定刷新率(比如 60Hz,即 1 秒刷新 60 次,约 16.67ms / 次)。RAF 的回调会精准对齐浏览器的刷新节奏,保证每帧只执行一次回调,避免 “过度渲染”(比如 1 秒执行 100 次,显示器根本显示不过来,纯浪费性能)。
requestAnimationFrame 的浏览器兼容性表现如下
在 现代主流浏览器(如 Chrome、Firefox、Safari、Edge 等)中,requestAnimationFrame 都能很好地支持 ,可以放心用于实现动画、页面高性能更新等场景,能适配大多数用户的浏览器环境 。
浙公网安备 33010602011771号