requestAnimationFrame 是实现高性能平滑动画的首选,它同步屏幕刷新率、自动节电、避免丢帧;需递归调用、利用时间戳控制速度、用 cancelAnimationFrame 正确停止。

在JavaScript中,requestAnimationFrame 是实现高性能、平滑动画的首选方式,它比 setTimeout 或 setInterval 更精准、更省资源,能自动适配屏幕刷新率(通常是60Hz),避免丢帧和卡顿。
为什么 requestAnimationFrame 更适合动画
浏览器会将 requestAnimationFrame 的回调安排在下一次重绘之前执行,并与显示器的刷新节奏同步。这意味着:
- 动画帧率稳定,基本锁定在 60fps(16.67ms/帧)
- 页面不可见时(如切换标签页),浏览器会自动暂停回调,节省 CPU 和电量
- 不会因 JS 执行阻塞而累积延迟,避免“一连串猛刷”的抖动现象
基础用法:一个标准的动画循环
关键点是**递归调用**——在每次回调结束前,再次请求下一帧:
function animate() {
// 更新状态(比如位置、透明度等)
element.style.transform = `translateX(${x}px)`;
<p>// 请求下一帧
requestAnimationFrame(animate);
}
requestAnimationFrame(animate); // 启动注意:不要用 setInterval(animate, 16) 模拟,它无法保证与刷新同步,且不节能。
立即学习“Java免费学习笔记(深入)”;
带时间控制的动画(推荐用于运动逻辑)
原生 requestAnimationFrame 回调会传入一个 DOMHighResTimeStamp(毫秒级时间戳),可用于计算真实经过时间,让动画速度与设备性能无关:
let lastTime = 0;
function animate(currentTime) {
if (!lastTime) lastTime = currentTime;
const deltaTime = currentTime - lastTime; // 单位:毫秒
lastTime = currentTime;
<p>// 例如:以 100px/s 的速度移动
x += (100 * deltaTime) / 1000;</p><p>element.style.transform = <code>translateX(${x}px)</code>;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);停止动画的正确方式
requestAnimationFrame 返回一个 ID,可用 cancelAnimationFrame(id) 中断。常见做法是保存 ID 并在需要时清除:
let animationId = null;
<p>function animate() {
// ... 动画逻辑
animationId = requestAnimationFrame(animate);
}</p><p>function stopAnimation() {
if (animationId !== null) {
cancelAnimationFrame(animationId);
animationId = null;
}
}特别注意:不要依赖闭包内局部变量来“取消”,务必显式管理 ID。
不复杂但容易忽略——用对了 requestAnimationFrame,动画就成功了一大半。










