应优先使用 requestAnimationFrame 替代 setTimeout/setInterval 实现动画,因其能对齐屏幕刷新率、避免掉帧;需避免布局抖动、慎用 will-change、优先 CSS 合成动画,并优化 Canvas 绘制性能。
requestAnimationFrame 替代 setTimeout 或 setInterval
浏览器对 requestAnimationFrame 有专门调度优化,能自动对齐屏幕刷新率(通常是 60fps),而 setTimeout 的执行时机不可控,容易掉帧甚至累积延迟。
常见错误是写成这样:
setInterval(() => {
element.style.transform = `translateX(${x}px)`;
}, 16);
应该改为:
function animate() {
x += 2;
element.style.transform = `translateX(${x}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
requestAnimationFrame 回调里做 DOM 查询(如 getB
oundingClientRect())、样式读取(如 offsetTop)或强制同步布局,否则触发重排(reflow)style
纯 CSS 动画(@keyframes + animation)由合成器线程处理,不阻塞主线程,比 JS 频繁修改 style.transform 更稳。
适用场景包括:循环动画、入场/出场动效、状态切换过渡。
transform 和 opacity,避免触发动画期间的重排(如 left、top、width)will-change: transform 可提前提示浏览器提升图层,但别滥用——长期开启会增加内存开销animation-play-state: paused 控制暂停,比反复启停 requestAnimationFrame 更轻量当 JS 在同一帧内交替读写布局相关属性(比如先读 offsetHeight,再改 style.height),浏览器被迫同步计算样式和布局,严重拖慢动画帧率。
getComputedStyle 替代 offsetXXX 等可能触发重排的属性(但仍属读操作,别混在写中间)ResizeObserver 替代轮询 offsetWidth 来响应尺寸变化Canvas 卡顿很少是因为 requestAnimationFrame 本身,多源于重复绘制未裁剪区域、频繁创建临时对象或未启用离屏缓存。
ctx.save()/ctx.restore() 替代重复设置 fillStyle/strokeStyleOffscreenCanvas 或 canvas 缓存,动画中只 blitctx.drawImage 绘制未预加载的图片——会触发同步解码ctx.setTransform(1, 0, 0, 1, 0, 0) 重置变换矩阵,比 ctx.resetTransform() 兼容性更好(IE/旧 Edge 不支持后者)