应共用单个 requestAnimationFrame 主循环驱动所有 canvas,以 timestamp 为统一时间源计算动画状态,并分离更新与绘制逻辑确保同步;各 canvas 上下文独立,浏览器自动合成。

用 requestAnimationFrame 控制多个画布动画同步执行,关键不是给每个画布单独调用 requestAnimationFrame,而是共用同一个动画帧循环——所有绘制逻辑统一在单次回调中完成。
共享一个 rAF 主循环
多个 <canvas> 元素应由同一个 requestAnimationFrame 回调驱动。这样它们天然共享浏览器的刷新节奏(通常 60fps),避免因各自调用导致的帧错位或时间漂移。
- 定义一个主渲染函数(如
render()),内部依次调用各画布的绘制逻辑 - 在该函数末尾再次调用
requestAnimationFrame(render)形成循环 - 不要为每个 canvas 写独立的
requestAnimationFrame(drawCanvas1)、requestAnimationFrame(drawCanvas2)—— 这会引入微小调度偏差,长期运行可能不同步
统一时间戳驱动动画状态
浏览器传入的 timestamp 参数是高精度单调递增的时间值(单位:毫秒),应作为所有动画的唯一时间源,用于计算位移、旋转、插值等。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
- 在主回调中接收
timestamp,并传给各画布的更新函数 - 各画布根据自身动画周期(如 2s 循环)用
timestamp % 2000计算当前相位,而非依赖setInterval或自增计数器 - 避免使用
Date.now()—— 它精度低且不保证单调性,可能在系统时间调整时跳变
分离更新与绘制,避免阻塞
复杂场景下,若某个画布的逻辑计算耗时较长,可能拖慢整体帧率。建议将“状态更新”和“像素绘制”分两步处理,并确保都在同一帧内完成。
立即学习“前端免费学习笔记(深入)”;
- 在
render(timestamp)开头批量更新所有动画对象的位置/属性(纯 JS 计算) - 再依次调用
canvas1Ctx.clearRect()、drawOnCanvas1()、drawOnCanvas2()等 - 若某画布需异步加载资源(如图片),先标记“未就绪”,跳过绘制,待
onload后触发一次requestAnimationFrame补帧
注意 canvas 的渲染上下文独立性
每个 <canvas> 有自己独立的 2D 或 WebGL 上下文,但它们的绘制操作不会互相干扰——只要你在主循环中按需调用各自的 ctx.drawImage()、ctx.fillRect() 等即可。
- 无需手动控制 GPU 同步或帧缓冲区;浏览器自动将所有
canvas绘制结果合成到最终页面帧 - 若发现视觉撕裂,检查是否启用了
canvas.style.imageRendering = 'pixelated'等影响渲染管线的样式 - 对性能敏感场景,可启用
will-change: transform提示浏览器优化合成层,但仅对频繁变换的 canvas 有效


















