IndexedDB 用 Promise 封装可解决异步嵌套问题,核心是将每个 request 的 onsuccess/onerror 映射为 resolve/reject;需注意事务不能跨 await 持有,必须在同步段内完成创建、操作与封装。

IndexedDB 本身是事件驱动的异步 API,直接使用 onsuccess/onerror 容易嵌套、难维护。用 Promise 封装后,配合 async/await,就能写出线性、可读、易错控的代码。
封装核心:把每个 request 包进 Promise
所有 IndexedDB 操作(open、add、get、put、delete)都返回一个 request 对象。它的 onsuccess 和 onerror 是天然的 resolve/reject 入口。
- open() 封装:在 onsuccess 中 resolve(db),onerror 或 onupgradeneeded 出错时 reject
- 事务内操作(如 store.get):确保先获取事务和 store,再对 request 做 Promise 包装
- 统一处理错误:reject 时尽量传 error 对象而非字符串,便于上层判断类型(如 AbortError、QuotaExceededError)
关键细节:事务不能跨 await 持有
IndexedDB 的事务生命周期极短——一旦当前调用栈执行完,事务就自动中止。所以不能这样写:
❌ 错误示范async function badExample() {
const tx = db.transaction('users', 'readonly');
const store = tx.objectStore('users');
await new Promise(r => setTimeout(r, 10)); // 等待后事务已关闭
return store.get(1); // 报错:Transaction inactive
- 正确做法:事务创建、store 调用、request 包装必须在同一个同步段完成
- 推荐结构:async 函数内立即启动事务 → 立即调用 store 方法 → 立即包装该 request 为 Promise
实用封装示例(精简版)
比如封装一个 getOne 工具函数:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
function getOne(db, storeName, key) {
return new Promise((resolve, reject) => {
const tx = db.transaction(storeName, 'readonly');
const store = tx.objectStore(storeName);
const req = store.get(key);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
使用时直接 await:
async function loadUser(id) {
const db = await openDB('myApp', 'users', 1);
return await getOne(db, 'users', id);
}
进阶建议:组合成链式或类实例
更进一步可封装成 DB 类或工具对象,预置 dbName/storeName/版本,支持链式调用:
- db.use('users').get(123)
- db.use('logs').add({ ts: Date.now(), msg: 'ok' })
- 内部仍走 Promise + 事务即时执行,但对外隐藏了重复逻辑
已有成熟轻量库如 idb(Jake Archibald 开发)就是这个思路,API 几乎与原生一致,却全面支持 await。

















