IndexedDB是浏览器端支持事务、索引和GB级存储的高性能本地NoSQL数据库,需通过合理建模、精准索引、分批写入与主动清理实现高效应用。

IndexedDB 是浏览器端最强大的本地数据库,适合存储结构化数据、支持事务、索引和大量数据(GB 级别在现代浏览器中已可行)。它不是简单“缓存”,而是可持久、可查询、可增删改查的客户端数据库。要真正用好它做高性能本地缓存,关键不在“存”,而在“怎么建模、怎么索引、怎么分片、怎么清理”。
合理设计 Object Store 与主键策略
每个数据库由多个 object store(类似表)组成。设计时避免“一个 store 存所有数据”的反模式:
- 按业务域拆分 store:例如
articles、user_profiles、offline_queues,便于权限控制和批量清理 - 主键(keyPath)优先选业务唯一字段(如
id),避免用自增数字——后者在多端同步或离线写入时易冲突 - 若需复合查询(如按 category + timestamp 范围查),不依赖主键,而用 multiEntry 索引 + keyRange
索引不是越多越好,但关键查询必须有对应索引
IndexedDB 查询性能极度依赖索引。没有索引的 get/all 查询只能全表扫描,海量数据下会卡死 UI 线程:
- 对高频过滤字段(如
status、updated_at、tenant_id)显式创建索引,设置unique: false和multiEntry: false即可 - 对时间范围查询(如“最近7天消息”),建立
updated_at索引后,用IDBKeyRange.bound(start, end)高效定位 - 避免在长文本字段(如
content)上建索引;全文搜索应交由FlexSearch或tantivy-wasm等专用库处理
分块写入 + 批量事务,防止阻塞主线程
一次性 put 10 万条记录会触发长时间事务,导致页面冻结甚至被浏览器终止:
- 将大数据集切分为每批 500–2000 条,用
transaction.objectStore().add()批量写入 - 每次写入后 await 下一个 transaction,利用微任务间隙让出主线程(可用
queueMicrotask或setTimeout(..., 0)控制节奏) - 开启事务时明确指定 scope:
db.transaction(['logs'], 'readwrite'),避免意外锁住无关 store
主动管理容量与生命周期,避免无限膨胀
IndexedDB 不会自动清理,长期运行的应用可能占满配额(通常为磁盘空间的 ~50%,但各浏览器差异大):
- 为每类数据设定 TTL(如缓存文章保留 30 天),插入时存
expiresAt字段,定期用游标遍历过期项并 delete - 监听
storage事件或使用navigator.storage.estimate()主动监控用量,接近限额(如 >80%)时触发分级清理(先删临时队列,再删旧日志) - 敏感数据(如 token、PII)绝不存 IndexedDB;必须存时,配合 Web Crypto API 加密后再写入
不复杂但容易忽略:IndexedDB 的错误不可忽视。所有 open、transaction、request 都要监听 onerror 和 onsuccess,失败时降级到内存 Map 缓存或报错提示,而不是静默失败。

















