离屏渲染关键在于分层合理、更新精准、尺寸匹配设备像素比;适合缓存内容需同时满足长期不变且单次绘制开销远高于drawimage,如静态ui、重复图元、固定贴图,伪静态内容应避免缓存。

离屏渲染不是让 Canvas “多画一次”,而是把该缓存的画一次、该复用的贴无数次。真正起效的关键,在于分层是否合理、更新是否精准、尺寸是否匹配设备像素比。
哪些内容适合放进离屏画布
核心判断标准就两条:内容长期不变 + 每次重绘开销远高于 drawImage。
- 静态 UI 层:地图边框、固定标题栏、HUD 控件、网格背景线
- 重复图元:上百个相同图标、统一风格的节点、带阴影/渐变的按钮模板
- 缩放/旋转频繁但内容固定的贴图:齿轮图标、瓦片底图、矢量装饰元素
- 伪静态要警惕:含微渐变、时间戳文字、动态噪点的内容,缓存无效,仍需每帧重绘
怎么建离屏画布才不踩坑
创建离屏 Canvas 最常见的错误是忽略显式尺寸和高 DPI 适配。Canvas 元素必须设置 width/height 像素值,不能靠 CSS 缩放,否则 getContext('2d') 可能返回 null 或渲染错位。
- 优先用 document.createElement('canvas') 创建,兼容性更好;new OffscreenCanvas() 在 Safari 和部分 WebView 中不可用
- 若主画布已按 window.devicePixelRatio 缩放(如 2x),离屏 Canvas 的 width/height 也必须设为 clientWidth × devicePixelRatio
- 避免调试中高频调用 toDataURL()——它强制光栅化+内存拷贝,反而引发卡顿
- 关闭图像平滑:ctx.imageSmoothingEnabled = false,尤其对线条、图标类图形更清晰
分层与更新策略决定实际收益
把整屏塞进一个离屏 Canvas 是典型低效做法。应按更新频率拆成 3–5 个逻辑层:
- background:几乎不动,建一次用到底
- static-ui:主题切换或语言包加载完成时批量重建
- dynamic-ui:用户操作局部刷新,仅保留在主 Canvas 渲染
- effects:粒子、拖影等每帧变化内容,不参与离屏缓存
更新只发生在必要时刻:监听主题色变更、精灵图 onload、缩放比例跳变超过阈值(如 1.0 → 1.8)。用脏矩形机制替代全层清空——记录变动区域坐标,clearRect 精确擦除再重绘。
性能兜底与资源管理
离屏渲染本质是用内存换时间,但失控的内存占用会反噬性能。
- 创建上下文时传入优化选项:getContext('2d', { willReadFrequently: false })
- 定期估算内存占用(如 offscreen.toDataURL().length),总量超 20MB 时启动 LRU 清理
- 对长期不用的离屏 Canvas,主动释放引用并调用 offscreen = null
- 监控离屏画布数量和总尺寸,避免因分层过细导致上下文创建开销反超收益











