IndexedDB.open()本质是发起版本控制事务:数据库不存在则创建v1;版本号升高则触发onupgradeneeded升级;相等或更低则直接success。必须处理onupgradeneeded、onsuccess和onerror,版本号须为正整数且不可降级。

IndexedDB open 方法到底做了什么indexedDB.open() 不是单纯“打开”数据库,它本质是发起一个版本控制事务:如果数据库不存在,就创建 v1;如果已存在但传入的版本号更高,就触发升级流程;如果版本号相等或更低,直接进入 success 回调(不升级)。关键点在于——**版本号只能升不能降,且必须是整数**。传 1.5 或 "2" 会静默失败或抛 InvalidStateError。
open 调用时必须处理 onupgradeneeded 和 onsuccess
只监听 onsuccess 是常见错误,会导致升级逻辑完全被跳过。正确做法是:
- 必须为
onupgradeneeded 绑定处理函数,否则旧库无法建新 objectStore
-
onsuccess 只在打开成功(含升级完成)后触发,此时才能安全执行读写
-
onerror 需兜底,比如用户禁用 IndexedDB 或磁盘满时会进这里
const request = indexedDB.open('mydb', 2);
request.onupgradeneeded = event => {
const db = event.target.result;
// 注意:event.oldVersion 是升级前的版本,v0 表示首次创建
if (event.oldVersion < 1) {
db.createObjectStore('users', { keyPath: 'id' });
}
if (event.oldVersion < 2) {
const store = db.transaction('users').objectStore('users');
store.createIndex('by_name', 'name', { unique: false });
}
};
request.onsuccess = () => {
const db = request.result; // 此时 db 已就绪,可读写
};
request.onerror = () => {
console.error('DB open failed:', request.error);
};
版本升级中不能复用旧 transactiononupgradeneeded 回调里的 event.target.result 是当前正在升级的 IDBDatabase 实例,它的内置 transaction 已绑定到升级上下文。常见错误是:
- 在
onupgradeneeded 里手动调用 db.transaction() 创建新 transaction → 报 InvalidStateError
- 试图在
onsuccess 里补建 objectStore → 永远不会生效,因为升级窗口已关闭
- 用
db.close() 中断升级流程 → 导致数据库处于半损坏状态
onsuccess 是常见错误,会导致升级逻辑完全被跳过。正确做法是:
- 必须为
onupgradeneeded绑定处理函数,否则旧库无法建新 objectStore -
onsuccess只在打开成功(含升级完成)后触发,此时才能安全执行读写 -
onerror需兜底,比如用户禁用 IndexedDB 或磁盘满时会进这里
const request = indexedDB.open('mydb', 2);
request.onupgradeneeded = event => {
const db = event.target.result;
// 注意:event.oldVersion 是升级前的版本,v0 表示首次创建
if (event.oldVersion < 1) {
db.createObjectStore('users', { keyPath: 'id' });
}
if (event.oldVersion < 2) {
const store = db.transaction('users').objectStore('users');
store.createIndex('by_name', 'name', { unique: false });
}
};
request.onsuccess = () => {
const db = request.result; // 此时 db 已就绪,可读写
};
request.onerror = () => {
console.error('DB open failed:', request.error);
};
版本升级中不能复用旧 transactiononupgradeneeded 回调里的 event.target.result 是当前正在升级的 IDBDatabase 实例,它的内置 transaction 已绑定到升级上下文。常见错误是:
- 在
onupgradeneeded 里手动调用 db.transaction() 创建新 transaction → 报 InvalidStateError
- 试图在
onsuccess 里补建 objectStore → 永远不会生效,因为升级窗口已关闭
- 用
db.close() 中断升级流程 → 导致数据库处于半损坏状态
onupgradeneeded 里手动调用 db.transaction() 创建新 transaction → 报 InvalidStateError onsuccess 里补建 objectStore → 永远不会生效,因为升级窗口已关闭 db.close() 中断升级流程 → 导致数据库处于半损坏状态 正确做法是:所有 schema 变更(createObjectStore、createIndex、deleteObjectStore)必须且只能在 onupgradeneeded 中通过 event.target.result 完成。
open 失败的典型场景和排查方向open 请求卡住或直接进 onerror,往往不是代码问题,而是环境限制:
- 浏览器隐私模式下部分 Chromium 内核会拒绝 IndexedDB(返回
UnknownError)
- iOS Safari 对非 HTTPS 页面禁用 IndexedDB(即使 localhost 也不行)
- 同一域名下多个标签页同时调用
open 且版本不同,可能触发 VersionChange 事件冲突
- 数据库名含非法字符(如空格、斜杠)→ 触发
InvalidCharacterError
UnknownError) open 且版本不同,可能触发 VersionChange 事件冲突 InvalidCharacterError 检查时优先打印 request.error?.name 和 request.error?.message,比猜更有用。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
升级逻辑本身没有“回滚”机制,设计时就得接受“一旦升级,旧版代码无法兼容读取新结构”。所以每次改 schema 前,得想清楚迁移路径——比如加字段要设默认值,删字段得先确保老数据已归档。


















