IndexedDB高效使用需Promise封装、显式事务管理与类型契约约束:统一异步模型,readonly/readwrite事务分离,getAll/游标替代循环get,TypeScript接口定义schema确保类型安全。

IndexedDB 原生 API 是事件驱动、回调导向的,直接写容易陷入多层嵌套,逻辑分散、错误难捕、事务难控。真正高效的做法不是“忍着用”,而是从结构上切断回调链——核心是统一异步模型、明确事务边界、封装模式可复用。
用 Promise 封装所有数据库操作
不手动监听 onsuccess/onerror,而是把每个 open、createObjectStore、get、put 等操作包装成返回 Promise 的函数。事务完成和失败统一由 transaction.oncomplete / onerror 控制,单个请求只负责 resolve 或 reject,不处理业务逻辑。
- openDB 返回 Promise
,失败时 reject 错误,不依赖 request.onsuccess - 每个读写方法(如 add、get、getAll)接收 store 名和数据,内部自动创建对应类型事务(readonly 或 readwrite)
- 事务内多个操作共用同一个 transaction,避免“一次操作开一次事务”的低效写法
事务生命周期必须显式管理
IndexedDB 的事务在事件循环空闲时自动关闭,不是语句执行完就结束。靠单个请求 success 回调判断完成是不可靠的;必须监听 transaction.oncomplete 和 onerror,并确保所有操作都在该事务上下文中发起。
- readwrite 事务中,连续调用 store.put() 多次,比开多个事务快 3–5 倍
- 查询类操作一律用 readonly 事务,避免意外阻塞写操作
- 事务出错时,整个事务回滚,不能只 catch 某个 put 的 reject —— 要在 transaction.onerror 统一拦截
提前定义数据库结构与类型契约
避免运行时 key 错误或 value 类型混乱。用 TypeScript 接口描述每个 objectStore 的 keyPath、value 结构及索引字段,再通过泛型约束所有增删改查方法。
- 定义 DBSchema 接口,为每个 store 明确 key 类型(string/number)和 value 形状
- add 方法签名类似 add
(storeName: string, value: T): Promise - 索引查询(index.get)也带类型推导,比如 getByIndex<User>('users', 'email', 'a@b.com')
批量操作优先使用游标或 getAll,而非循环调用 get
需要读取一组记录时,不要 for + get,这会触发多次独立请求和事务调度。应使用 getAll、openCursor 或 IDBKeyRange 配合游标一次性获取。
- getAll() 适合数量可控(
- 大数据集用 cursor 迭代,配合 event.preventDefault() 防止默认行为干扰
- 范围查询用 IDBKeyRange.bound(start, end, false, true),比多次 get 更精准且高效

















