用 promise 封装 indexeddb 可将回调地狱转为链式调用或 async/await,核心是将 request.onsuccess/onerror 转为 resolve/reject;需安全处理 open(含版本升级、upgradeneeded、错误统一 reject)、crud(每次新建事务、区分 add/put、get/getall/delete/update)、错误增强(附操作上下文)及 typescript 泛型支持。

用 Promise 封装 IndexedDB 能把回调地狱变成链式调用或 async/await,核心是把 request.onsuccess 和 request.onerror 转成 Promise 的 resolve/reject。
封装 open:安全打开数据库
IndexedDB 的 open 操作本身就有版本升级逻辑,容易出错。封装时需处理版本变更、升级事务和兼容性(如旧版 IE 不支持 Promise)。
- 用
indexedDB.open(dbName, version)启动; - 监听
upgradeneeded创建/更新 objectStore,确保表结构就绪; - 在
success回调中返回已打开的db实例; - 统一 reject 所有错误(包括 blocked、versionchange 等),避免静默失败。
封装通用 CRUD 方法:复用事务和请求
每个增删改查都依赖事务(transaction),不能复用 db 对象直接操作,必须每次新建 transaction 并指定 store 名称和模式(readwrite / readonly)。
-
add / put:用
transaction.objectStore(store).add(item),区分 add(主键冲突报错)和 put(覆盖); -
get / getAll:支持 key 或 IDBKeyRange,
store.get(key)返回单个,store.getAll()或store.getAll(IDBKeyRange.bound(...))返回数组; -
delete:传入 key 或 key range,
store.delete(key); - update:本质是 put,但建议封装为先 get 再修改再 put,或直接用 put 覆盖(需确保主键存在)。
统一错误处理与类型提示
IndexedDB 错误信息模糊(如 AbortError、UnknownError),建议包装成带上下文的 Error 对象。
- 在每个 request 的
onerror中 reject,并附上操作类型("get user by id")、store 名、key 值; - TypeScript 下可定义泛型方法,如
get<t>(store: string, key: IDBValidKey): Promise<t undefined></t></t>; - 避免在事务外访问 result —— Promise resolve 必须等 request 完成,不是事务完成。
示例:一个最小可用的封装类
不依赖第三方库,仅用原生 API:
class IDBHelper {
constructor(dbName, version, upgradeCb) {
this.dbName = dbName;
this.version = version;
this.upgradeCb = upgradeCb;
}
async open() {
return new Promise((resolve, reject) => {
const req = indexedDB.open(this.dbName, this.version);
req.onupgradeneeded = (e) => {
const db = e.target.result;
this.upgradeCb?.(db, e.oldVersion, e.newVersion, e.transaction);
};
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
req.onblocked = () => reject(new Error('DB blocked – close other tabs'));
});
}
async get(storeName, key) {
const db = await this.open();
return new Promise((resolve, reject) => {
const t = db.transaction(storeName, 'readonly');
const req = t.objectStore(storeName).get(key);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
async add(storeName, value) {
const db = await this.open();
return new Promise((resolve, reject) => {
const t = db.transaction(storeName, 'readwrite');
const req = t.objectStore(storeName).add(value);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
}
// 使用
const db = new IDBHelper('myapp', 1, (db) => {
if (!db.objectStoreNames.contains('users')) {
db.createObjectStore('users', { keyPath: 'id' });
}
});
const user = await db.get('users', 123);
await db.add('users', { id: 456, name: 'Alice' });
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











