构建原子性本地持久化层需复用同一IndexedDB事务实例,监听oncomplete/onabort事件,分块批量写入,并封装为Promise。

要构建具备原子性的本地持久化层,核心是把多个数据操作绑定在同一个 IndexedDB 事务中——任一失败,全部不生效。
事务必须显式开启且复用同一实例
IndexedDB 不会自动合并操作。每次调用 db.transaction(...) 都创建一个新事务,彼此隔离、互不回滚。真正实现原子性,必须:
- 只调用一次
db.transaction(storeName, 'readwrite')获取事务对象 - 所有
add()、put()、delete()都通过该事务的 objectStore 发起 - 不为每条数据新建事务,否则就是“伪批量”,毫无原子保障
监听事务级事件,而非单个请求事件
事务成功与否,取决于整个事务生命周期,不是单个 add 请求的成功。关键在于:
- 监听
transaction.oncomplete:表示事务内所有请求完成且已提交 - 监听
transaction.onabort:任一操作报错、或手动调用transaction.abort()时触发,此时所有变更已撤销 - 避免只监听每个
request.onsuccess——它只说明该请求发出了,不代表事务最终成功
批量写入需分块,兼顾原子性与稳定性
单事务塞入上万条记录容易触发浏览器限制(如内存溢出、事务超时、事件循环空闲导致自动终止)。稳妥做法是:
- 按固定大小切分数据,例如每 100–200 条为一块
- 每块使用独立事务执行,块之间用
Promise.all()或串行 await 控制流程 - 注意:多事务之间不具跨事务原子性;若要求“全量成功或全量失败”,必须压进一个事务(仅适用于中小数据量)
封装成 Promise 并配合 async/await 简化控制流
原生事件回调易嵌套出错。推荐封装事务操作为 Promise:
- 将
oncomplete映射为resolve(),onabort和onerror映射为reject() - 对外暴露
bulkAdd(db, storeName, items)这类语义清晰的方法 - 上层业务可用
await bulkAdd(...)同步感知成败,便于组合复杂持久化逻辑(如“先删旧数据,再插新数据”必须包在同一事务里)

















