直接用 URL.createObjectURL() 而不用 base64,因其体积小、内存开销低、渲染快;但需及时调用 revokeObjectURL() 防泄漏,且 revoke 不能过早或遗漏,否则导致加载失败或内存泄漏。

为什么直接用 URL.createObjectURL() 而不用 base64?
因为 base64 字符串体积比原始二进制大 ~33%,且每次生成都会复制数据到内存;URL.createObjectURL() 返回的是一个指向内存中 Blob 的引用地址,开销小、渲染快,适合临时展示。
但注意:这个 URL 是“一次性”的,必须在不再需要时调用 URL.revokeObjectURL() 释放引用,否则会持续占用内存(尤其在频繁生成图片的场景下)。
- 不 revoke → 内存泄漏风险,Chrome DevTools 的 Memory 面板能看到
Detached DOM tree积累 - revoke 过早 →
img加载失败,控制台报net::ERR_FILE_NOT_FOUND或空白 - 只对本域有效,不能跨域用于
canvas.toDataURL()等后续操作
如何从 canvas 动态生成 Blob 并显示在 img 上?
这是最常见场景:你画好了 canvas,想立刻转成图片展示,又不想走服务器。
关键点在于:canvas.toBlob() 是异步的,不能直接返回 Blob;而 img.src 必须等 Blob 创建完成才能赋值。
const canvas = document.getElementById('myCanvas');
// ... 绘制逻辑
<p>canvas.toBlob(blob => {
if (!blob) return;
const url = URL.createObjectURL(blob);
const img = document.getElementById('preview');
img.src = url;</p><p>// ✅ 正确时机:加载成功后再 revoke
img.onload = () => URL.revokeObjectURL(url);
// ❌ 错误:这里立刻 revoke,img 还没开始加载
// URL.revokeObjectURL(url);
}, 'image/png');</p>
img.src 赋值后图片不显示?检查这三件事
不是代码写错,而是容易忽略的隐性条件:
-
canvas宽高是 CSS 值而非实际像素尺寸 —— 用canvas.width/canvas.height设置真实分辨率,否则导出模糊或裁剪 -
toBlob()的 MIME 类型不被浏览器支持 —— 比如传'image/webp'但 Safari 旧版不认,降级用'image/png' -
img元素未挂载到 DOM 或已被移除 ——img.onload不会触发,建议加img.onerror捕获失败
如果图片要多次复用(比如下载 + 预览),别反复 create/revoke
同一个 Blob 可以生成多个 URL,但每个 URL 都要单独 revoke。更稳妥的做法是:把 Blob 存起来,按需创建 URL,并统一管理生命周期。
例如:
let currentBlob = null;
<p>function updatePreview(newBlob) {
if (currentBlob) URL.revokeObjectURL(URL.createObjectURL(currentBlob));
currentBlob = newBlob;
const url = URL.createObjectURL(newBlob);
img.src = url;
img.onload = () => { /<em> 可选:延迟 revoke,留出重绘余量 </em>/ };
}</p>
真正麻烦的不是生成,而是清理时机——尤其是单页应用里组件卸载、路由跳转时,onload 可能永远不触发,得配合 AbortController 或组件 unmount 钩子主动 revoke。











