事务作用域与提交
IndexedDB 的写请求完成,不等于事务已经持久化。只有 transaction.oncomplete 触发后,才可以把本次写入当作 durable 成功。
最小实验:等待事务提交
html
<pre id="log"></pre>
<script>
const log = (value) => document.querySelector('#log').textContent += value + '\n'
const request = indexedDB.open('lesson-idb', 1)
request.onupgradeneeded = () => request.result.createObjectStore('items', { keyPath: 'id' })
request.onerror = () => log(`open error: ${request.error.name}`)
request.onsuccess = () => {
const db = request.result
const tx = db.transaction('items', 'readwrite')
tx.objectStore('items').put({ id: 1, text: 'saved' })
tx.oncomplete = () => { log('commit complete'); db.close() }
tx.onerror = () => log(`transaction error: ${tx.error?.name ?? 'unknown'}`)
tx.onabort = () => log('transaction aborted')
}
</script>第一次运行应输出 commit complete。把 put 改成缺少 id 的对象,观察事务进入错误或中止;刷新后重新打开数据库,确认只有提交成功的数据可读。
机制与边界
事务只在自己的作用域和活动时段内有效。不要把事务对象跨越异步空闲随意保存;需要多个写入时,在同一事务中安排请求,并以 oncomplete 作为整体成功信号。版本升级期间还要处理其他标签页阻塞,否则新 schema 无法切换。
练习
- 在同一事务中写入两条记录,让第二条故意违反约束,验证第一条也不会部分提交。
- 添加读取事务,比较
onsuccess与oncomplete的含义。 - 打开两个标签页测试版本升级,记录
onblocked并设计提示用户关闭旧页面的恢复路径。