indexeddb 是浏览器中用于存储大量结构化数据的异步 api,需通过打开数据库、版本升级定义对象仓库与索引、事务内执行增删改查操作;不支持同步调用,需手动处理事件与错误,兼容性需注意 safari 限制。

JavaScript 在浏览器中使用 IndexedDB 存储结构化数据,核心是通过异步 API 创建数据库、对象仓库(object store)、索引,并执行增删改查操作。它适合存储大量结构化数据(如用户配置、离线缓存、日志等),但不能直接用 localStorage 那种简单方式调用——必须走打开数据库 → 创建/升级结构 → 事务操作 的流程。
打开数据库并处理版本升级
IndexedDB 使用版本号控制结构变更。首次打开或版本号升高时,会触发 onupgradeneeded 事件,在其中定义对象仓库和索引。
示例:
const request = indexedDB.open('myAppDB', 2); // 版本号设为 2
request.onerror = () => console.error('打开失败');
request.onsuccess = (event) => {
const db = event.target.result;
console.log('数据库已就绪', db);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 若旧版无 'users' 仓库,或版本从 1 升到 2,这里会执行
if (!db.objectStoreNames.contains('users')) {
// keyPath 指定主键字段(自动填充,不可重复)
const store = db.createObjectStore('users', { keyPath: 'id' });
// 添加索引,支持按 name 或 email 快速查询
store.createIndex('byName', 'name', { unique: false });
store.createIndex('byEmail', 'email', { unique: true });
}
};
在事务中执行数据操作
所有读写都必须在事务(IDBTransaction)中进行。事务有三种模式:readonly(默认)、readwrite、versionchange(仅 onupgradeneeded 内可用)。
常用操作方式:
-
添加数据:用
add()(主键冲突报错)或put()(覆盖同主键) -
读取单条:用
get(key),返回 Promise-like 的请求对象 -
按索引查询:先获取索引,再用
index.get(value)或index.getAll() -
遍历全部:用
openCursor(),适合大数据量分页或批量处理
示例(添加与查询):
function addUser(db, user) {
const tx = db.transaction('users', 'readwrite');
const store = tx.objectStore('users');
const req = store.add(user); // user 必须含 id 字段
req.onsuccess = () => console.log('用户已存入');
}
function findUserByEmail(db, email) {
const tx = db.transaction('users', 'readonly');
const store = tx.objectStore('users');
const index = store.index('byEmail');
const req = index.get(email);
req.onsuccess = () => console.log('查到用户:', req.result);
}
错误处理与兼容性注意
IndexedDB 是异步且事件驱动的,不支持 await 原生语法(需包装成 Promise)。常见陷阱包括:
- 未监听
onerror和onabort,导致失败静默 - 在
onsuccess中误用event.target.result(只对open有效;其他操作要用req.result) - 事务生命周期短——所有请求必须在事务对象仍有效时发起,否则报
TransactionInactiveError - Safari 对
deleteDatabase和某些索引行为支持较弱,上线前建议真机测试
简易 Promise 封装(供参考):
function promisifyRequest(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 使用示例
const db = await promisifyRequest(indexedDB.open('myDB', 1));
const tx = db.transaction('users', 'readonly');
const user = await promisifyRequest(tx.objectStore('users').get(123));
关闭与删除数据库
页面关闭时,数据库连接会自动释放,一般无需手动 close()。但若需主动清理:
-
db.close():关闭当前连接(不影响其他标签页) -
indexedDB.deleteDatabase('dbName'):彻底删除数据库(会触发onblocked,需确保无其他连接)
删除前可监听 onblocked 提示用户刷新页面:
const deleteReq = indexedDB.deleteDatabase('myAppDB');
deleteReq.onblocked = () => alert('请关闭其他使用此数据库的页面后重试');Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











