优雅取消 requestAnimationFrame 的关键是保存ID并及时调用 cancelAnimationFrame,需防叠加、清内存、配生命周期,确保启停成对、作用域清晰、可控。

要优雅地取消 requestAnimationFrame 动画,核心是保存上一次调用返回的 ID,并在合适时机调用 cancelAnimationFrame —— 但关键在于**及时清理、避免重复调用、防止内存泄漏和逻辑错乱**。
保存并管理 requestAnimationFrame 的 ID
每次调用 requestAnimationFrame 都会返回一个唯一数字 ID,必须保存下来才能后续取消:
- 不要用局部变量存储(如函数内声明),否则外部无法访问
- 推荐用闭包、实例属性或模块级变量维护当前动画 ID
- 每次发起新动画前,先检查并取消前一个(防叠加)
封装可取消的动画循环
把启动、更新、停止逻辑收拢,避免散落各处:
class AnimationLoop {
#id = null;
#callback = null;
start(cb) {
this.stop(); // 确保无残留
this.#callback = cb;
const step = () => {
if (this.#callback()) { // 返回 true 继续,false 停止
this.#id = requestAnimationFrame(step);
}
};
this.#id = requestAnimationFrame(step);
}
stop() {
if (this.#id !== null) {
cancelAnimationFrame(this.#id);
this.#id = null;
this.#callback = null;
}
}
}
// 使用
const loop = new AnimationLoop();
loop.start((time) => {
// 动画逻辑,返回 true 表示继续
return element.style.transform = `translateX(${time % 200}px)`;
});
// 随时调用
loop.stop();
在组件卸载或状态变更时自动清理
尤其在 React、Vue 或自定义元素中,务必在生命周期结束时取消:
- React:在
useEffect的清理函数中调用cancelAnimationFrame - Vue:在
onBeforeUnmount中清理 - 自定义元素:在
disconnectedCallback中处理 - 避免依赖未挂载的 DOM 节点或已销毁的对象
注意 cancelAnimationFrame 的容错性
cancelAnimationFrame 本身是幂等的,传入无效 ID 不会报错,但仍建议做空值判断:
- 传入
null、undefined或已过期 ID 安全,但不改变行为 - 不必为“是否已取消”加额外标记,直接调用即可
- 调试时可打印 ID 对比,确认 cancel 和 rAF 是同一轮次
真正优雅的关键不在语法多精巧,而在于从设计上让“启动”和“停止”成对出现、作用域清晰、生命周期可控。不复杂但容易忽略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











