登录
首页 >  文章 >  前端

JavaScript动画技巧:requestAnimationFrame使用教程

时间:2026-05-20 21:22:47 240浏览 收藏

前往漫画官网入口并下载 ➜
本文深入解析了 requestAnimationFrame 这一浏览器原生动画调度机制的核心价值与实战要点:它并非简单的“动画函数”,而是通过精准对齐屏幕刷新节奏(如60fps或120fps)、自动暂停不可见标签页、避免强制同步布局,实现更顺滑、更节能的动画体验;文章对比了其与 setTimeout 的本质差异,详解了递归调用的必要性、cancelAnimationFrame 的正确终止方式,并直击开发者常踩的时间精度偏差、DOM 查询滥用、多动画冗余调度等陷阱,强调真正关键的是将动画逻辑解耦为可预测、可中断、帧率无关的小步更新——帮你从“能动”迈向“专业可控”。

javascript如何实现动画_requestAnimationFrame如何使用【教程】

requestAnimationFrame 不是“用来做动画的函数”,而是浏览器提供的、**让动画更顺滑且节能的调度机制**。直接用 setTimeoutsetInterval 做动画,容易掉帧、卡顿、耗电,而 requestAnimationFrame 会把回调对齐到屏幕刷新节奏(通常是 60fps),且在页面不可见时自动暂停。

为什么动画要用 requestAnimationFrame 而不是 setTimeout

核心区别在于调度时机和生命周期管理:

  • setTimeout(fn, 16) 是“尽力而为”:系统忙时延迟可能远超 16ms,导致跳帧;空闲时又可能触发多余调用
  • requestAnimationFrame(fn) 是“听屏幕指挥”:只在下一帧绘制前执行,且标签页切走后自动暂停,不浪费 CPU 和电量
  • 动画逻辑中若涉及 DOM 读写(比如先 getBoundingClientRect()style.transform),requestAnimationFrame 还能避免强制同步布局(forced reflow)

requestAnimationFrame 的基本用法和终止方式

它不是循环 API,每次只调用一次回调,要实现持续动画,必须在回调内部再次调用自己 —— 这是关键习惯。

function animate() {
  // 更新元素位置/样式
  element.style.transform = `translateX(${x}px)`;

  // 关键:递归请求下一帧
  if (isAnimating) {
    requestAnimationFrame(animate);
  }
}
// 启动
requestAnimationFrame(animate);

终止动画不能靠“清空定时器 ID”,因为 requestAnimationFrame 返回的是一个数字 ID,但取消它必须用 cancelAnimationFrame(id)

  • 保存上一次调用返回的 ID:let rafId = requestAnimationFrame(animate);
  • 停止时调用:cancelAnimationFrame(rafId);
  • 漏掉 cancelAnimationFrame 可能导致内存泄漏或意外重绘(尤其组件卸载时)

实际动画中容易踩的坑

写出来能跑 ≠ 写得对。常见问题集中在时间控制、状态管理和精度上:

  • performance.now() 计算真实经过时间,别依赖“每帧 16ms”——设备可能降频、高刷屏是 120fps、后台标签页帧率极低
  • 不要在 requestAnimationFrame 回调里做大量计算或 DOM 查询,否则挤占绘制时间,反而卡顿
  • 多个动画共存时,别每个都开独立 requestAnimationFrame 循环;应合并到同一个主动画帧中统一更新
  • CSS 动画(transition / @keyframes)比 JS 动画更高效,优先用 CSS;JS 仅用于需要运行时逻辑(如跟随鼠标、物理模拟)的场景

真正难的不是调用 requestAnimationFrame,而是把动画逻辑拆解成“可预测、可中断、与帧率解耦”的小步更新 —— 尤其涉及 easing、暂停/恢复、时间缩放时,很容易陷入手动维护时间戳和状态的泥潭。

文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《JavaScript动画技巧:requestAnimationFrame使用教程》文章吧,也可关注golang学习网公众号了解相关技术文章。

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>