indexeddb 是浏览器中真正的本地数据库引擎,用于离线、高并发、大数据量下的结构化数据管理;它支持异步操作、大容量存储、原生对象存取、acid事务及索引快速查询,而 localstorage 仅适合小量字符串存储。

IndexedDB 不是 localStorage 的“升级版”,而是浏览器里真正意义上的本地数据库引擎。它解决的不是“存点小数据”的问题,而是“在离线、高并发、大数据量场景下,安全、高效、可查询地管理结构化数据”的问题。
为什么必须用 IndexedDB 而不是 localStorage?
localStorage 同步写入几 MB 数据会卡住整个页面;它只能存字符串,每次都要 JSON 序列化;没有事务,转账扣款+加款可能只执行一半;无法按字段查,只能全量遍历过滤。而 IndexedDB:
- 异步操作,完全不阻塞 UI 线程
- 单库容量可达数百 MB 甚至数 GB(Chrome 默认允许源占用磁盘 80%)
- 直接存对象、数组、Blob、File、TypedArray,无需手动序列化
- 支持 ACID 事务,一组操作要么全成功,要么全回滚
- 通过索引实现 O(log n) 查询,比如按 user.email 或 order.status 快速筛选
核心概念:五个不可跳过的抽象层
理解这五层,就掌握了 IndexedDB 的骨架:
- Database(数据库):每个域名可建多个,带版本号(如 v1、v2),结构变更必须靠升级触发
- Object Store(对象仓库):相当于 NoSQL 中的“集合”,不设 schema,但需指定主键方式(keyPath 或 autoIncrement)
-
Index(索引):非默认存在,必须显式创建;想按
title查,就得调用store.createIndex('by_title', 'title') - Transaction(事务):所有读写都必须包裹在事务中;事务有作用域(只影响指定 store)、有模式(readonly / readwrite / versionchange)
-
Cursor(游标):用于遍历或分页;比 for...of 更底层,支持范围扫描(
IDBKeyRange.bound('a', 'z'))和方向控制(nextunique)
实战开发关键流程:从打开到读写
原生 API 基于事件,但现代项目建议用 idb(轻量 Promise 封装库)简化逻辑。典型流程如下:
- 调用
idb.openDB('MyAppDB', 2, { upgrade })打开或升级数据库 - 在
upgrade回调中:创建 objectStore、添加索引、迁移旧数据(如把 v1 的users表字段扩展) - 写入时用
transaction.objectStore('notes').add({ id: 1, content: 'hello', ts: Date.now() }) - 查询时先获取索引:
store.index('by_ts').getAll(IDBKeyRange.upperBound(Date.now())) - 删除/更新也必须走事务,不能直接操作 store
容易踩坑的四个细节
这些点不写文档里,但线上故障常源于此:
- 事务生命周期极短——离开函数作用域自动 commit,别在回调里延迟操作
- 索引字段值为
undefined时,该记录不会进入索引,查不到;可用{ multiEntry: true }处理数组字段 - versionchange 事务不能被 await,必须在
onupgradeneeded里同步建表,否则报错 - 大量数据导入时,避免单次 add 1000 条;应分批(如每 50 条一个事务),防止内存溢出或事务超时











