requestAnimationFrame 与屏幕刷新率在 Canvas 动画中的影响
在 Web 开发中,Canvas 是实现高性能绘图和动画的主要工具,而 `requestAnimationFrame`(rAF)是 Canvas 动画中控制帧更新的标准方法。理解 rAF 与屏幕刷新率的关系,对于保证 Canvas 动画的流畅性和一致性至关重要。
1. rAF 在 Canvas 动画中的作用
当使用 Canvas 绘制物体移动时,每一帧的更新通常包含以下步骤:
- 清空画布(或覆盖上一帧内容)
- 计算物体位置
- 绘制物体
- 请求下一帧
典型代码如下:
javascript
let x = 0;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
x += 2; // 移动速度
ctx.fillRect(x, 50, 50, 50);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
这里 requestAnimationFrame 控制每次 Canvas 绘制的执行时机。
2. 屏幕刷新率对 Canvas 动画的影响
requestAnimationFrame 会尽量与屏幕刷新同步,因此其调用频率与显示器刷新率直接相关:
- 60Hz 屏幕:每秒约 60 帧(每帧 ~16.7ms)
- 120Hz 屏幕:每秒约 120 帧(每帧 ~8.3ms)
如果动画逻辑直接依赖每次 rAF 调用更新位置(例如 x += 2),则:
- 在高刷新率屏幕上,物体移动速度会更快(每秒移动距离翻倍)
- 在低刷新率屏幕上,物体移动速度会更慢
这会导致动画在不同设备上表现不一致。
3. 使用时间差保证动画一致性
为了保证 Canvas 物体移动在不同刷新率屏幕上速度一致,应该使用 rAF 提供的时间戳参数(timestamp)来计算每帧的时间间隔,并按时间间隔调整移动距离:
javascript
let lastTime = 0;
let x = 0;
function animate(timestamp) {
if (!lastTime) lastTime = timestamp;
const delta = timestamp - lastTime; // 帧间时间差
lastTime = timestamp;
ctx.clearRect(0, 0, canvas.width, canvas.height);
x += 0.1 * delta; // 根据时间差控制速度
ctx.fillRect(x, 50, 50, 50);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
这样,无论屏幕刷新率是 60Hz 还是 144Hz,物体移动速度都保持一致。
4. 其他注意事项
- 动画平滑性:使用 rAF 保证绘制与屏幕刷新同步,避免撕裂和跳帧。
- 性能优化:Canvas 动画不需要每帧重绘整个画布,可以只重绘移动区域,节省 CPU/GPU 资源。
- 高刷新率适配:在 120Hz 或更高刷新率屏幕上,如果仍按固定像素移动,物体可能显得移动过快,因此必须使用时间差计算。
5. 总结
在 Canvas 动画中,requestAnimationFrame 的调用频率受到屏幕刷新率影响。若不考虑时间差直接按帧更新位置,动画在不同设备上会出现快慢不一的问题。正确做法是使用 rAF 的时间戳参数,通过时间差计算物体位移,保证在各种刷新率设备上的动画表现一致,同时保持渲染与屏幕同步,实现流畅、平滑的移动效果。