核心是Worker做计算、主线程做合成;OffscreenCanvas必须由主线程transferControlToOffscreen()移交或Worker内new创建(Chrome/Edge支持,Firefox需开启标志),2D上下文fillText静默失败,WebGL需desynchronized:true且readPixels不可用。
核心是把图形计算和像素绘制完全移出主线程,让 dom 保持响应。offscreencanvas 本身不缓解压力,只有配合 web worker 才真正起效——主线程只管 ui 交互和最终合成,其余全交给后台线程。
必须在 Worker 中创建或移交 OffscreenCanvas
主线程里 new OffscreenCanvas(width, height) 没用,它还是绑定在主线程执行环境里。真正释放压力的路径只有两条:
- 已有页面
:主线程调用canvas.transferControlToOffscreen(),再通过postMessage(data, [offscreen])把控制权完整转移给 Worker - 纯离屏渲染:Worker 内直接调用
new OffscreenCanvas(width, height)(Chrome/Edge 全支持;Firefox 需开启gfx.offscreencanvas.enabled)
Worker 内安全初始化上下文
不同上下文类型行为差异大,不能照搬主线程写法:
-
2D 上下文:调用
offscreen.getContext('2d')即可,支持fillRect、putImageData;但fillText会静默失败,文字需提前光栅化或由主线程绘制 -
WebGL 上下文:必须传
{ desynchronized: true },否则可能初始化失败;readPixels不可用(返回黑图),应避免;texImage2D推荐接收ImageBitmap或TypedArray
资源加载与帧循环由 Worker 主导
所有资产都不能依赖主线程 DOM 加载:
- 图片资源:主线程用
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)等方式约束











