可以直接用 indexeddb 存储动态图片和多媒体资源,关键在于 blob 直存、哈希去重、分片上传、流式读取,避免转 base64 和内存溢出;图片≤200mb 直存,超限则分片;音视频采用“元数据+分片”双表结构,单片 2–4mb;读取时优先用 url.createobjecturl 或 blob.stream(),慎用 arraybuffer();需处理版本升级、事务错误及隐私模式降级。

可以直接用 IndexedDB 存储动态图片(如 Canvas 导出的 Blob、fetch 下载的 PNG/JPEG)和多媒体资源(音频、视频),关键在于不转 base64、合理分片、流式读取,避免内存爆掉或写入失败。
存储图片:Blob 直存 + 哈希去重
动态生成的图片(比如 canvas.toBlob() 或截图)直接作为 Blob 存入,无需转字符串。用文件名或内容哈希(如 SHA-256)作主键,防止重复缓存:
- key 推荐用 URL 路径哈希 或 canvas 内容指纹,避免同名不同图覆盖
- 对象存储(objectStore)配置
{ keyPath: 'id' },插入时传{ id: 'img_abc123', imageData: blob } - 单张图建议 ≤200MB;超过则走分片(见下文),普通背景图、头像图基本都远小于此
缓存多媒体:按需分片 + 元数据管理
视频或大音频文件不宜整块存——浏览器事务可能超时,内存也可能撑不住。推荐“元数据 + 分片”双表结构:
- 建两个 objectStore:
media_files(存名称、总大小、MIME、分片数、创建时间等)和media_chunks(每片 2–4MB,key 为${mediaId}_${index}) - 上传时用
File.slice()拆分,逐片写入;事务控制在 1–2 片/次,避免长时间挂起 - 查询某资源所有分片可用
IDBKeyRange.bound('vid_abc_0', 'vid_abc_99999'),高效且不遍历全库
读取与使用:优先走 stream,慎用 arrayBuffer()
从 IndexedDB 取出 Blob 后,不要立刻调 blob.arrayBuffer() —— 对 100MB 视频,这会把全部数据拉进内存:
- 显示图片:用
URL.createObjectURL(blob)直接赋给<img src>,浏览器自动管理释放 - 播放视频/音频:
<video src="blob:xxx"></video>即可;如需流式解码,用blob.stream()接入ReadableStream管道 - 局部处理(如裁剪首帧、提取缩略图):调
blob.slice(0, 500000)取前 500KB,再转 Blob URL,不加载全文
健壮性补充:版本升级与错误兜底
IndexedDB 的 onupgradeneeded 是唯一能改 schema 的时机,升级时注意兼容旧数据:
- 新增索引(如按 mimeType 查询)要在 upgrade 中创建,否则 get() 以外的查询会报错
- 写入失败常见原因:事务超时(Chrome 默认 60s)、Blob 过大、磁盘满;捕获
transaction.onabort和request.onerror,降级到 fetch 重试 - 隐私模式下 IndexedDB 不可用,需提前检测:
if (!('indexedDB' in window)) { /* fallback */ }











