应使用 requestanimationframe 而非 settimeout/setinterval,因其对接 vsync、适配任意刷新率;回调中必须用传入的时间戳计算 deltatime 实现帧率无关动画;清屏用 clearrect 并确保使用 canvas.width/height;避免动画中触发强制同步布局。

用 requestAnimationFrame 而不是 setTimeout 或 setInterval
高刷新率屏幕(如 90Hz、120Hz、144Hz)下,setTimeout(fn, 16) 会彻底失效:它不感知屏幕节奏,16ms 是硬编码,实际执行可能漂移甚至连续挤在同一次 VSync 内,造成撕裂或卡顿。而 requestAnimationFrame 由浏览器直接对接 GPU 的 VSync 信号,无论屏幕是 60Hz 还是 144Hz,回调都严格落在下一帧绘制前——这是防撕裂的底层前提。
常见错误现象:
- 写
setInterval(animate, 10)试图“追上”120Hz → 实际触发不可控,主线程一忙就丢帧,且后台仍跑,耗电 - 没传参、没算
deltaTime,直接写x += 2→ 在 120Hz 屏上速度翻倍,在 30Hz 屏上慢成幻灯片
requestAnimationFrame 回调里必须用时间戳做匀速校准
浏览器传给 requestAnimationFrame 回调的第一个参数是 currentTime(DOMHighResTimeStamp),单位毫秒,精度远高于 Date.now()。忽略它,等于放弃帧率无关性。
正确做法是记录上一帧时间,算出真实流逝毫秒数:
let lastTime = performance.now();
function animate(currentTime) {
const deltaTime = currentTime - lastTime;
lastTime = currentTime;
<p>// 目标:每秒移动 100px
x += (100 / 1000) * deltaTime;</p><p>ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x, y, 20, 20);</p><p>requestAnimationFrame(animate);
}
requestAnimationFrame(animate);</p>
注意:lastTime 初始化用 performance.now(),而非 0,否则首帧 deltaTime 可能异常大。
Canvas 清屏必须用 clearRect,且范围要对
撕裂感有时不是帧率问题,而是像素残留。用 ctx.fillRect(0, 0, width, height) 填背景色清屏,会盖掉 CSS 设置的 background-image,且在透明 canvas 上叠加出灰雾;而 clearRect 是真正擦除像素,语义准确、无副作用。
容易踩的坑:
- 清屏时用了 CSS 设置的宽高(
canvas.style.width),但clearRect需要的是 DOM 属性canvas.width和canvas.height—— 二者不一致会导致清错区域、拖影明显 - 动画只动局部区域(比如一条流动线),却清全屏 → 白耗 GPU 带宽;应只清脏矩形:
clearRect(x, y, w, h) - 没缓存
getContext('2d'),每次重绘都重新获取 → 微小但累积的开销,在高频帧下可测出延迟
避免强制同步布局,否则再高的刷新率也白搭
哪怕你跑满 144fps,只要在 requestAnimationFrame 回调里读 offsetTop、getBoundingClientRect() 或连续写 style.left + style.top,浏览器就会立刻 flush 样式、强制同步回流(layout),打断渲染流水线,帧率瞬间崩到 20fps 以下。
实操要点:
- 所有 DOM 尺寸/位置读取,集中到帧开头一次性缓存(如
const {width, height} = canvas) - 所有样式写入,集中到帧末尾批量处理(如合并为
element.style.transform = `translate(${x}px, ${y}px)`) - 绝对不要在动画循环里调用
getComputedStyle、clientWidth、scrollIntoView - 如果 canvas 上需叠加 HTML 元素动画,优先用
transform和opacity,它们走合成层,不触发布局
高刷屏放大了每一个微小的 layout 误操作——它不给你“差不多”的余地。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











