JavaScript 中 requestAnimationFrame() 深度解析与实战应用
本文深入解析 JavaScript 中的 requestAnimationFrame() 方法,阐述其如何与浏览器刷新率同步以实现流畅动画。通过对比 setTimeout 和 setInterval,说明其在节能、后台暂停及避免卡顿方面的优势,并提供多元素同步动画及取消动画的完整代码示例。
requestAnimationFrame() 是 JavaScript 中用于实现动画效果的重要 API。它通知浏览器即将执行动画,并请求浏览器在下次重绘之前调用指定的回调函数以更新动画状态。相较于传统的 setTimeout 和 setInterval,requestAnimationFrame() 能够提供更高效的执行机制和更流畅的视觉体验。
基本概念
1. 浏览器的重绘和回流
浏览器采用“帧”机制来渲染页面内容,通常目标帧率为每秒 60 帧(60FPS)。每一帧的渲染过程包括计算布局、样式以及将内容绘制到屏幕。requestAnimationFrame() 专为这一过程设计,它确保动画代码在浏览器的重绘周期内执行,从而使每次动画更新与浏览器的刷新频率保持同步。
2. 效率和节能
requestAnimationFrame() 会根据显示器的物理刷新率自动调节帧率,常见标准为 60FPS。若显示器刷新率为 60Hz,requestAnimationFrame() 每秒将回调约 60 次。当浏览器窗口被最小化或切换到其他标签页时,requestAnimationFrame() 会自动暂停执行,从而降低 CPU 和 GPU 的负载。这与 setTimeout、setInterval 不同,后者无论页面是否可见都会持续运行。
使用方法
let start = null;
function step(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
// 更新动画的位置,这里是简单的例子,假设移动一个物体
const element = document.getElementById('box');
element.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`;
if (progress < 2000) { // 继续动画,直到经过2秒
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
示例详解
1. 回调函数
requestAnimationFrame() 接收一个回调函数作为参数,该函数将在浏览器准备好绘制下一帧时被触发。在示例代码中,step 函数即充当此回调角色。
2. timestamp 参数
浏览器会向回调函数传递一个 timestamp 参数,代表当前请求的动画帧开始时的时间戳。该 timestamp 以毫秒为单位的高精度时间值,可用于精确计算动画的时间差。
3. 递归调用
在 step 函数内部,我们通过 requestAnimationFrame() 自身调用自身,构建动画的递归循环。每次触发 requestAnimationFrame(step),浏览器将在下一帧重新执行 step 函数。
4. 条件控制
为了停止动画,可以在递归调用时加入条件判断。例如在示例中,通过 progress < 2000 控制动画持续 2 秒。若缺少此条件,动画将无限循环执行。
与 setTimeout 和 setInterval 的比较
function moveBoxWithSetTimeout() {
let position = 0;
const element = document.getElementById('box');
function update() {
position += 5;
element.style.transform = `translateX(${position}px)`;
if (position < 200) {
setTimeout(update, 1000 / 60); // 每秒60次更新
}
}
update();
}
function moveBoxWithRequestAnimationFrame() {
let position = 0;
const element = document.getElementById('box');
function update() {
position += 5;
element.style.transform = `translateX(${position}px)`;
if (position < 200) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
区别:
时间控制:
setTimeout(update, 1000 / 60)人为指定每秒 60 帧,但实际性能受浏览器和 CPU 限制,未必精准。requestAnimationFrame()由浏览器根据系统负载决定最佳帧率,并与显示器刷新同步。
后台标签页处理:
setTimeout和setInterval在后台标签页或最小化时仍继续运行,造成资源浪费。requestAnimationFrame()会在页面不可见时暂停执行,有效节省资源。
流畅度:
setTimeout和setInterval因无法与浏览器重绘同步,易导致动画卡顿或抖动。requestAnimationFrame()能提供更为平滑的动画效果。
多个动画场景
你可以通过 requestAnimationFrame() 同时控制多个动画。只需确保每个动画逻辑在回调函数中被正确处理即可。
let box1 = document.getElementById('box1');
let box2 = document.getElementById('box2');
let start = null;
function animate(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
box1.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`;
box2.style.transform = `translateY(${Math.min(progress / 20, 300)}px)`;
if (progress < 2000) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
上面的代码演示了:
box1向右移动,每 10 毫秒移动一个像素,直到移动 200 像素。box2向下移动,每 20 毫秒移动一个像素,直到移动 300 像素。
多个元素的动画可以在同一个 requestAnimationFrame 回调中进行,这样它们会同步进行,保证帧率的一致性。
动画的取消
requestAnimationFrame() 返回一个唯一的整数 ID,代表该动画帧请求。可以使用 cancelAnimationFrame() 取消这个动画。
let animationId;
function step(timestamp) {
// 动画逻辑
if (progress < 2000) {
animationId = requestAnimationFrame(step);
}
}
// 开始动画
animationId = requestAnimationFrame(step);
// 取消动画
cancelAnimationFrame(animationId);
总结
- 同步与浏览器刷新频率:
requestAnimationFrame()是与显示器的刷新率同步的动画方法,通常会以 60FPS 执行。 - 高效与节能:在页面不可见时,
requestAnimationFrame()会暂停执行,避免不必要的计算。 - 流畅的动画体验:由于它与浏览器的重绘同步,能带来更加流畅的动画效果。
通过掌握 requestAnimationFrame(),你可以更轻松地创建流畅且高效的动画效果,它是现代 Web 动画开发的核心工具之一。
到此这篇关于js中requestAnimationFrame()解读与使用示例的文章就介绍到这了,更多相关js requestAnimationFrame()内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
anime.js 快速入门:怎么引入库并编写第一个 DOM 动画
2026-11-05 14:22:43
在线JS解密后变量名仍乱码?结合浏览器DevTools调试还原
2026-11-04 20:26:01
怎么在浏览器中运行JavaScript代码并查看输出结果
2026-11-04 09:07:33
JS 获取屏幕分辨率:window.screen.width 与 height 用法
2026-11-04 08:52:48
为什么推荐用DOMContentLoaded代替window.onload初始化JS
2026-11-04 08:42:33
