JavaScript动画核心是每帧更新元素状态并以60fps重绘,requestAnimationFrame因与浏览器渲染机制协同、对齐重绘时机、自适应刷新率而比setInterval更流畅。

用 JavaScript 实现动画效果的核心,是**在每一帧中更新元素的视觉状态(比如位置、透明度、缩放等),并让浏览器以接近 60fps 的节奏重绘**。而 requestAnimationFrame(简称 rAF)之所以比 setInterval 更流畅,根本原因在于它**与浏览器的渲染机制深度协同**,而不是靠固定时间间隔“硬塞”更新。
动画的本质:不是“定时执行”,而是“跟帧走”
浏览器渲染页面是一个周期性流程:接收输入 → 运行 JS → 计算样式和布局 → 绘制图层 → 合成显示。这个流程每秒尝试执行约 60 次(即 16.67ms/帧)。理想动画,就是每次都在“绘制前”完成状态更新,确保每一帧都呈现最新画面。
-
setInterval(fn, 16)只是“尽量每 16ms 调用一次 fn”,但 JS 执行可能卡顿、任务队列堆积、甚至跨帧执行,导致多次更新挤在单帧里,或一帧内漏掉更新 —— 表现为掉帧、抖动、延迟感。 -
requestAnimationFrame(fn)则把回调交给浏览器调度:浏览器保证在**下一次重绘之前**执行该函数,且自动根据设备刷新率调整(如 iPad Pro 120Hz 下约 8.3ms/帧),天然对齐渲染节奏。
用 requestAnimationFrame 写一个基础位移动画
以下是一个平滑移动 表面看 立即学习“Java免费学习笔记(深入)”;const box = document.getElementById('box');
let position = 0;
const endPosition = 400;
function animate() {
if (position < endPosition) {
position += 2; // 每次移动 2px
box.style.transform = `translateX(${position}px)`;
requestAnimationFrame(animate); // 下一帧继续
}
}
requestAnimationFrame(animate); // 启动
setTimeout 或 setInterval 控制节奏,全由浏览器决定何时调用下一次 animate。setInterval 仍运行,造成无效计算。
为什么 setInterval 容易“假流畅”
setInterval(fn, 16) 数值上接近 60fps,但实际存在多个隐性问题:
setInterval 仍固执地按 16ms 跑,要么浪费资源,要么超负荷掉帧。补充建议:让动画更专业
transform + opacity 属性,它们可被 GPU 加速,rAF 只负责控制逻辑(如触发、暂停、插值)。performance.now() 记录起始时间,在 rAF 回调中计算已过去毫秒数,再算出当前进度 —— 而非依赖帧数累加。offsetTop)或大量 DOM 操作,防止强制同步布局,拖慢帧率。











