将渲染计算移至worker并配合offscreencanvas可真正缓解主线程压力:worker通过offscreencanvas离屏绘制,用imagebitmap零拷贝回传,需注意上下文限制、资源加载及dpr适配。

用 OffscreenCanvas + Worker 实现离屏绘制
主线程不能直接在 Worker 里画图,必须通过 OffscreenCanvas 建立桥梁:
- 已有
<canvas></canvas>:主线程调用canvas.transferControlToOffscreen(),再用postMessage(offscreen, [offscreen])把控制权完整移交 Worker - 纯离屏场景:Worker 内直接
new OffscreenCanvas(width, height)(Chrome/Edge 全支持;Firefox 需开启gfx.offscreencanvas.enabled) - 注意:
new OffscreenCanvas()写在主线程里毫无意义——它仍绑定主线程执行环境,起不到卸载作用
Worker 内安全使用图形上下文
不同上下文行为差异大,不能照搬主线程写法:
- 2D 上下文:
offscreen.getContext('2d')可用fillRect、putImageData,但fillText会静默失败;文字需提前光栅化或由主线程绘制 - WebGL 上下文:必须传
{ desynchronized: true },否则可能初始化失败;readPixels不可用(返回黑图),应避免;推荐用texImage2D接收ImageBitmap或TypedArray
图像资源与帧循环全由 Worker 主导
所有资产加载和节奏控制都不能依赖主线程:
- 图片:主线程用
fetch + createImageBitmap()解码后,以postMessage(bitmap, [bitmap])转移进 Worker - 着色器/顶点数据:Worker 自行
fetchGLSL 文本并编译,或由主线程编译好传入二进制程序对象 - 帧率控制:Worker 内不能用
requestAnimationFrame,改用setTimeout或setInterval;每帧结尾建议调用gl.flush()防止命令积压
高效回传画面,避免拷贝瓶颈
渲染结果不会自动上屏,必须显式同步:
- 优先用
offscreen.transferToImageBitmap()截帧,该方法异步且零拷贝;但本身有开销,建议每 2–3 帧触发一次,或只在内容变化时调用 - 主线程收到
ImageBitmap后,直接用ctx.drawImage(bitmap, 0, 0)绘制到可见 canvas;支持缩放、平移、旋转等变换,无需重新光栅化 - 注意尺寸与 DPR 控制:iOS Safari 和部分 WebView 对单纹理尺寸有硬限制(通常 ≤ 4096px),高 DPR 设备易超限闪退,逻辑尺寸需按
Math.min(width, 4096 / devicePixelRatio)等方式约束











