requestAnimationFrame 不是定时器,掉帧主因是误当 setInterval 使用;正确做法是用其时间戳计算 deltaTime、仅操作合成属性、避免重排与同步阻塞。
requestAnimationFrame 不是“更高级的 setInterval”,它根本就不是定时器——用错思路,动画照样掉帧、卡顿、跨设备表现不一致。
为什么 requestAnimationFrame 会掉帧?
掉帧不是因为函数写错了,而是你把它当成了
的替代品来“轮询”:比如在回调里固定加
,再手动控制间隔。这完全违背了它的设计逻辑。
真实掉帧原因有三个:
没传时间戳参数,导致无法计算帧间耗时(
),位移量无法随设备刷新率自适应
在回调中执行了重排(reflow)操作,比如反复读取
或修改非合成层样式(如
、
)
动画函数内做了大量同步计算或 DOM 插入,阻塞了下一帧的准备时机
怎么写一个真正稳帧的 animate 函数?
核心就两件事:用好时间戳 + 控制渲染路径。下面是最小可用模板:
立即学习
“
前端免费学习笔记(深入)
”;
注意几个关键点:
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
必须接收
参数,这是浏览器传入的真实高精度时间戳(单位 ms)
不要用
或
自己取,它们和 rAF 不对齐
启动只需一次
,不是
再调一次
别在动画函数里调
或做 layout 触发操作(如
)
requestAnimationFrame 和 canvas 动画怎么配合?
canvas 动画最容易出问题的地方是“清画布”和“绘制顺序”。常见错误是每帧都全量重绘,或者漏清残留图像。
正确做法:
每帧开头必须调用
,否则上一帧内容会残留
如果只动局部图形(比如一个小球),可以用
/
配合
精确控制绘制范围
避免在
中频繁创建新路径或对象(如每次 new Path2D()),复用已有实例
canvas 尺寸要用
/
设置,别只靠 CSS 缩放,否则模糊+性能降级
cancelAnimationFrame 容易被忽略的细节
很多人以为只要存下
返回的 ID 就能随时停掉动画,但有两个坑:
ID 是一次性有效的:调用
后,该 ID 失效;再次
会返回新 ID,旧 ID 不再起作用
没清理 ID 变量会导致内存泄漏:比如组件卸载后,动画还在后台跑,ID 还挂在闭包里 —— 必须显式设为
或用 WeakMap 管理
页面不可见时,
会自动暂停(符合规范),但 resume 时不保证时间戳连续,所以
计算要容错(比如限制最大值为 100ms)
真正可靠的启停模式是封装成状态机,而不是靠裸 ID 控制。
setIntervalthis.x += 2deltaTimeoffsetLeftlefttoplet lastTime = 0;
function animate(currentTime) {
const deltaTime = currentTime - lastTime;
lastTime = currentTime;
// ✅ 用 deltaTime 做时间敏感更新(比如每秒移动 120px)
ball.x += (120 / 1000) * deltaTime;
// ✅ 渲染只做 transform + opacity(触发合成层)
ballEl.style.transform = translateX(${ball.x}px);
// ✅ 下一帧继续
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
currentTimeDate.now()performance.now()requestAnimationFrame(animate)animate()console.loggetBoundingClientRectctx.clearRect(0, 0, canvas.width, canvas.height)ctx.save()ctx.restore()ctx.beginPath()animatecanvas.widthcanvas.heightrequestAnimationFramecancelAnimationFrame(id)requestAnimationFramenullrequestAnimationFramedeltaTime