HTML5中requestAnimationFrame动画应递归调用并传入时间戳,用deltaTime实现匀速运动;需用isRunning控制暂停、cancelAnimationFrame停止防泄漏;兼容旧浏览器可回退setTimeout。

在 HTML5 中,标准的 requestAnimationFrame 动画循环应以递归调用方式实现,确保与浏览器刷新节奏同步,并支持暂停、终止和时间差计算。
基础结构:递归调用 + 时间戳参数
浏览器会自动将时间戳(DOMHighResTimeStamp)作为唯一参数传入回调函数,这是计算帧间耗时的可靠依据,避免使用 Date.now() 或 performance.now() 手动取值带来的误差。
标准写法如下:
function animate(timestamp) {
// 计算自上一帧以来经过的时间(毫秒)
if (!lastTime) lastTime = timestamp;
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
<p>// 更新逻辑(如位置、旋转、状态)
update(deltaTime);</p><p>// 渲染逻辑(如 canvas 绘图、DOM 修改)
render();</p><p>// 请求下一帧
animationId = requestAnimationFrame(animate);
}
let lastTime = 0;
let animationId = 0;
animationId = requestAnimationFrame(animate);</p>添加控制能力:启动、暂停、停止
直接递归调用无法中途暂停。需封装为可管理的对象或函数,配合布尔标志和取消机制:
立即学习“前端免费学习笔记(深入)”;
- 用
let isRunning = true控制是否继续调用requestAnimationFrame - 暂停时不清除
animationId,仅跳过下一次请求;恢复时重新调用requestAnimationFrame - 停止时必须调用
cancelAnimationFrame(animationId)防止内存泄漏
适配不同刷新率:用 deltaTime 做匀速运动
动画效果(如每秒移动 100px)必须基于 deltaTime 计算,而非固定步长。例如:
// 错误:帧率高时快,低时慢 x += 2; <p>// 正确:目标速度 60px/s,与帧率无关 const speedPxPerSecond = 60; x += (speedPxPerSecond * deltaTime) / 1000;</p>
兼容性与健壮性建议
- 在旧浏览器中可回退到
setTimeout(..., 1000/60),但需自行模拟时间戳 - 避免在
update或render中执行耗时操作(如大量 DOM 查询、复杂计算),否则可能掉帧 - 若需精确帧率控制(如锁 30fps),可在回调中判断
timestamp % 33 < 16等方式节流,但非常规需求



















