离屏渲染需用内存换时间,仅内容变更时重绘,否则更卡;OffscreenCanvas 兼容性差,应改用 document.createElement('canvas') 并显式设置 width/height;高 DPI 下须同比例缩放像素尺寸;避免每帧重绘、合理分层与 dirty 标志位可提升性能。

离屏渲染不是加个 OffscreenCanvas 就变快,而是用内存换时间——只在内容真变了才重画,其余全靠 drawImage 复制,否则反而更卡。
OffscreenCanvas 构造失败返回 null 怎么办
直接调用 new OffscreenCanvas(100, 100) 在 Safari 和多数安卓 WebView 中会失败,getContext('2d') 返回 null。这不是 bug,是兼容性现实。
- 永远用
document.createElement('canvas')创建离屏画布,它在所有现代浏览器中都可用 - 必须显式设置
width和height属性(不是 CSSstyle.width),否则上下文可能不可用或绘制区域为 0×0 - 别对
transferControlToOffscreen()返回的句柄调用getContext——它只能传给 Worker,不能在主线程继续操作
高 DPI 设备下离屏画布模糊或裁剪
主 Canvas 若用了 window.devicePixelRatio 缩放(比如设了 canvas.width = canvas.clientWidth * devicePixelRatio),离屏 Canvas 的像素尺寸也必须同比例放大。否则 drawImage 时会拉伸、模糊,或只显示左上角一小块。
- 错误写法:
offscreen.width = canvas.clientWidth - 正确写法:
offscreen.width = canvas.clientWidth * window.devicePixelRatio,同理处理height - 如果主 Canvas 是 CSS 缩放(如
style="width: 500px; height: 300px;"),离屏尺寸必须按实际渲染像素算,不能照抄 CSS 值 - 调试时可临时把离屏 Canvas 插入 DOM 并加
border,确认其实际绘制区域是否匹配预期
为什么用了离屏反而更卡
性能下降几乎总是因为“每帧都重绘离屏画布”,等于把一次绘制拆成两次,还多占内存。真正起效的前提是:内容长期不变 + 更新时机被严格控制。
立即学习“前端免费学习笔记(深入)”;
- 别在
requestAnimationFrame回调里无条件调用offscreenCtx.clearRect()+ 全量重绘 - 只监听真实变更源:主题切换事件、语言包加载完成、图片
onload、配置项change,而不是每帧检查img.complete - 分层管理:把动态元素和静态背景画在同一离屏画布上,会导致一动全重绘;应拆成“背景层”“图标模板层”“连接线层”等独立缓存单元
- 引入
dirty标志位,仅当底层数据或样式真正变化时,才触发对应层的重绘
提升离屏绘制效率的关键配置
获取上下文时传入选项能带来可观收益,但默认行为往往不是最优。
-
getContext('2d', { alpha: false }):关闭透明度支持,GPU 渲染提速 5–10%,适用于纯色背景或不需混合的场景 -
getContext('2d', { desynchronized: true }):启用异步渲染模式,减少主线程阻塞,对动态内容提升约 15% - 避免
willReadFrequently: true:除非真要用getImageData读像素,否则开启会降低 20% 性能 -
ctx.imageSmoothingEnabled = false:尤其对图标、线条类图形更清晰,避免缩放模糊 - 离屏上下文不继承主 Canvas 的状态,每次使用前需手动设置
font、fillStyle等,不能省略
最容易被忽略的点是:离屏画布不是“画完就完事”,它需要和主画布在像素级对齐、在更新节奏上严格同步、在内存占用上主动兜底——否则缓存越大,卡得越稳。



















