IndexedDB需工程化设计:按业务域分store、用业务主键作keyPath、关键字段建索引、分批事务写入、主动清理与容量监控、敏感数据加密存储。

IndexedDB 不是“高级 localStorage”,而是一套需要工程化设计的本地数据库系统。它真正发挥作用,不靠简单存取,而靠结构规划、索引治理、事务节奏和生命周期管控。
按业务域拆分 Object Store,避免单表膨胀
把所有数据塞进一个 store 是最常见也最危险的设计。比如用户配置、聊天记录、离线任务队列混存在同一仓库里,不仅清理困难,还会因锁竞争拖慢写入。
- 推荐按功能边界建 store:user_settings、chat_messages、offline_actions、draft_documents
- 每个 store 的 keyPath 应优先选业务主键(如 message_id、draft_uuid),而非 autoIncrement 数字——后者在多端同步或离线补传时极易冲突
- 对临时性数据(如上传队列),可设独立 store 并配专用清理策略,不影响核心数据稳定性
索引不是越多越好,但关键查询必须有支撑
没有索引的 get/all 查询等于全表扫描,10 万条记录就可能卡住 UI。IndexedDB 的性能瓶颈几乎都出在索引缺失或误用上。
- 为高频过滤字段建索引:status、category、updated_at、tenant_id —— 均设 unique: false
- 时间范围查询(如“最近 3 天”)要配合 IDBKeyRange.bound(start, end),前提是 updated_at 已建索引
- 避免在长文本字段(content、description)上建索引;全文检索交给 FlexSearch 或 tantivy-wasm 等专用库
分批写入 + 明确事务范围,守住主线程响应性
一次性写入数万条记录会触发长时间事务,浏览器可能直接终止操作。真正的高吞吐不是“一次写完”,而是“稳住节奏”。
- 将大数据集切分为每批 500–2000 条,用 transaction.objectStore().add() 批量提交
- 每次写入后让出主线程:可用 queueMicrotask(() => nextBatch()) 或 setTimeout(() => nextBatch(), 0)
- 开启事务时务必限定 scope:db.transaction(['logs'], 'readwrite'),防止意外锁住无关 store 影响其他模块
主动清理 + 容量监控,防止静默占满配额
IndexedDB 不会自动释放空间。长期运行的应用若无清理机制,可能在某次更新后突然报 quota exceeded。
- 为缓存类数据添加 expiresAt 字段,定期用游标遍历并 delete 过期项
- 调用 navigator.storage.estimate() 监控用量,当 usage / quota > 0.8 时触发分级清理(先删临时日志,再删旧快照)
- 敏感数据(token、手机号、加密密钥)绝不明文存入;必须存时,用 Web Crypto API 加密后再写入

















