最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何用 IndexedDB 存储图片 Blob 并读取实现离线相册
时间:2026-07-26 16:57:53 编辑:袖梨 来源:一聚教程网
IndexedDB 可直接存储 Blob,需用 transaction 的 objectStore 以二进制方式写入,避免 base64 转换;创建 objectStore 时应设 keyPath: null 或合理配置键策略;读取后须立即调用 URL.createObjectURL() 并妥善管理生命周期,防止内存泄漏与离线失效。
IndexedDB 能直接存 Blob,但必须用 transaction 的 objectStore 以二进制方式写入,不能转成 base64 字符串——否则体积膨胀约 33%,且读取后还要手动 decode,得不偿失。
存图片 Blob 前先确保数据库结构支持二进制
IndexedDB 默认支持 Blob,但必须在创建 objectStore 时不设 keyPath 或显式允许任意键(如用 {keyPath: null, autoIncrement: true}),否则插入时可能因键缺失报 InvalidStateError。另外,store.put(blob, key) 的 key 最好是字符串(如文件名或 UUID),避免用数字 ID 配合 autoIncrement 后再手动覆盖——Blob 本身不含元数据,键就是你后续找图的唯一线索。
- 用
createObjectStore('photos', {keyPath: 'id'})时,每个 Blob 必须包装成对象:{id: 'IMG_001.jpg', data: blob, timestamp: Date.now()} - 若想直存 Blob,改用
{keyPath: null},然后调用store.put(blob, 'IMG_001.jpg') - 务必在
onupgradeneeded中定义 store,升级时旧版本 store 不会自动继承新配置
读取时 Blob 会保持原始类型,但需注意 URL 生命周期
从 IndexedDB 读出的仍是原生 Blob,可直接传给 URL.createObjectURL() 渲染到 <img>。但这个 URL 是临时引用,页面刷新即失效;如果用户离线打开相册,又没做预加载,仅靠 createObjectURL 无法持久化显示——必须在读取后立刻生成 URL,并缓存其字符串(blobUrl),同时监听 pagehide 或 beforeunload 主动 URL.revokeObjectURL(),否则内存泄漏风险明显。
- 不要在渲染循环里反复调用
createObjectURL,应读一次 Blob,生成一次 URL,存在组件 state 或 Map 中复用 - Chrome 对单页中同时存在的
blob:URL 数量有限制(通常 ~500),超出后旧 URL 可能被静默回收 - 服务端返回的图片若带
Content-Disposition: attachment,部分浏览器可能拒绝生成有效 URL,建议统一用fetch(...).then(r => r.blob())构造标准 Blob
离线场景下 get() 失败常见于事务提前关闭
IndexedDB 的 get() 必须在活跃事务内执行,而事务会在所有请求完成、事件循环空闲后自动关闭。如果在 request.onsuccess 里异步处理(比如用 setTimeout 或 Promise.then),此时事务早已结束,再调用 get() 就会报 TransactionInactiveError。这不是权限或存储空间问题,而是时序陷阱。
- 所有读写操作必须链在同一个
transaction内,或明确用transaction.objectStore('photos').get(key)并立即处理onsuccess - 避免在 async/await 函数里混用 IndexedDB 回调 API;如要用 await,封装成 Promise:
const getPhoto = (db, key) => new Promise((resolve, reject) => { const tx = db.transaction('photos', 'readonly'); const store = tx.objectStore('photos'); const req = store.get(key); req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error);}); - 离线时
open()本身可能失败(如用户禁用存储权限),需检查event.target.error.name === 'UnknownError'或'VersionError',而非只捕获网络错误
真正麻烦的不是存或取,而是用户清缓存时 IndexedDB 和 blob: URL 两者不同步——前者保留,后者消失。如果你把 URL 字符串存在 IndexedDB 里下次直接用,那它早就 404 了。所以每次展示前,哪怕是从 DB 读出了 Blob,也得重新走一遍 createObjectURL 流程,别图省事跳过。
相关文章
- 晴空双子500关通关阵容推荐 晴空双子传说级T0阵容搭配与实战解析 07-30
- 辉光之城1907好玩吗 辉光之城1907核心玩法与新手入门指南 07-30
- 未定事件簿主线第十八章行至黎明(上)即将开放 07-30
- 晴空双子爬塔阵容搭配指南 晴空双子高效率通关塔层阵容推荐 07-30
- 生存33天本周礼包码(1月12日) 07-30
- 原神月之四版本全新圣遗物介绍 07-30