JavaScript中的requestAnimationFrame与动画优化
字数 560 2025-11-14 13:13:44
JavaScript中的requestAnimationFrame与动画优化
描述
requestAnimationFrame是浏览器提供的专门用于实现高性能动画的API。它会在浏览器下一次重绘之前调用指定的回调函数,确保动画更新与浏览器的绘制周期同步,从而避免不必要的重绘和布局计算。
核心概念
-
传统动画实现方式(如setTimeout/setInterval)的问题:
- 执行频率不稳定(可能因主线程阻塞而延迟)
- 即使页面不可见仍会执行,浪费资源
- 容易引起布局抖动和过度重绘
-
requestAnimationFrame的优势:
- 自动匹配显示器刷新率(通常60fps)
- 页面未激活时自动暂停,节省资源
- 浏览器会批量优化连续的重绘操作
实现步骤
- 基础动画循环结构:
function animate() {
// 更新动画状态
updateAnimation();
// 请求下一帧
requestAnimationFrame(animate);
}
// 启动动画
requestAnimationFrame(animate);
- 具体实现示例(移动方块):
const element = document.getElementById('box');
let position = 0;
function moveBox(timestamp) {
// 计算位移(每秒100像素)
position += 100 / 60; // 按60fps计算每帧位移
// 应用变换
element.style.transform = `translateX(${position}px)`;
// 判断是否继续动画
if (position < 1000) {
requestAnimationFrame(moveBox);
}
}
// 开始动画
requestAnimationFrame(moveBox);
高级应用
- 时间戳参数的使用:
let startTime;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
// 基于时间差计算进度,避免帧率波动影响动画速度
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / 2000, 1); // 2秒完成
// 使用缓动函数
element.style.opacity = easeInOutCubic(progress);
if (progress < 1) {
requestAnimationFrame(animate);
}
}
- 性能优化技巧:
let lastTime = 0;
const fps = 30; // 限制帧率
function throttledAnimate(timestamp) {
if (timestamp - lastTime < 1000 / fps) {
requestAnimationFrame(throttledAnimate);
return;
}
lastTime = timestamp;
// 执行动画逻辑
updateAnimation();
requestAnimationFrame(throttledAnimate);
}
最佳实践
- 在动画开始前检查是否需要继续:
function animate() {
if (!element.isVisible) { // 自定义可见性检查
return;
}
// 动画逻辑
requestAnimationFrame(animate);
}
- 使用cancelAnimationFrame取消动画:
let animationId;
function startAnimation() {
animationId = requestAnimationFrame(animate);
}
function stopAnimation() {
cancelAnimationFrame(animationId);
}
注意事项
- 避免在requestAnimationFrame中执行耗时操作
- 对于复杂动画考虑使用CSS动画或Web Animations API
- 移动端注意电池续航,适当降低动画频率
通过requestAnimationFrame实现的动画更加平滑高效,是现代Web动画的首选方案。