requestAnimationFrame 是浏览器原生 API,用于在下一次重绘前执行动画回调;它由浏览器调度,自动适配刷新率、后台暂停、节电状态,避免 setTimeout 的定时不准、后台耗电、不同步丢帧等问题。
requestAnimationFrame 是浏览器提供的原生 API,用于在下一次重绘前执行回调函数。它不是“自己控制帧率”,而是把动画逻辑交给浏览器调度——浏览器知道当前刷新率(比如 60Hz)、是否页面在后台、设备节电状态等,自动决定何时触发回调。
用 setTimeout 或 setInterval 模拟 60fps(即每 16.6ms 执行一次)看似可行,但实际会出问题:
setTimeout 还在跑,浪费 CPU 和电量requestAnimationFrame 天然规避这些——它只在浏览器准备重绘前调用,且页面隐藏时自动暂停。
核心是「递归调用 + 状态更新」。不要把它当成一次性函数,而是一个持续驱动的循环入口。
let startTime = null; const duration = 2000; // 动画总时长 2sfunction animate(currentTime) { if (!startTime) startTime = currentTime; const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); // 归一化进度 [0, 1]
// 更新元素位置(示例:水平移动) const element = document.getElementById('box'); element.style.transform =
translateX(${progress * 300}px);if (progress < 1) { requestAnimationFrame(animate); // 继续下一帧 } }
// 启动 requestAnimationFrame(animate);
注意点:
requestAnimationFrame(animate)),不是 requestAnimationFrame(animate())
currentTime(由浏览器提供的时间戳)计算进度,而非依赖 Date.now(),更精准progress ),否则无限递归
它不替代 CSS @keyframes,而是补充那些 CSS 做不了的事:比如跟随鼠标实时计算路径、物理模拟(弹性、重力)、滚动视差、Canvas 绘图动画等。
关键区别:
reque
stAnimationFrame 提供 JS 层控制权,可读取 DOM 尺寸、响应用户输入、动态调整参数,灵活性强但需小心性能常见误用:用它反复设置 element.style.left/top 触发 layout → paint → composite 全流程。应优先用 transform 和 opacity,它们只触发 composite,更轻量。
requestAnimationFrame 在现代浏览器中已无兼容问题(IE10+ 支持,且有成熟 polyfill),但两个细节常被跳过:
cancelAnimationFrame(id) 主动停止(比如组件卸载、用户交互中断)startTime 和结束判断,避免互相干扰例如,一个轮播组件切换时没 cancel 上一个 requestAnimationFrame,旧动画回调仍可能执行并覆盖新状态——这种竞态很难 debug。