Promise.all中单个Promise被拒时如何终止其余操作并回滚?
核心原理说明
Promise本身不支持取消已启动的异步任务,你调用Promise.all时传入的所有Promise实例在创建的那一刻就已经开始执行了,因此Promise.all报错终止仅会中断后续的结果接收逻辑,已经执行的操作不会自动撤销。要实现「任意任务失败,所有修改都不生效」的效果,需要根据场景选择延迟提交修改或者事务回滚的方案。
Demo代码场景解决方案
针对修改内存变量的场景,最简单的方案是延迟修改原变量,所有异步逻辑先输出临时结果,等全部Promise执行成功后再合并到原变量中,代码示例如下:
exports.myFunction = async () => { const array = [] try { const p1 = Promise.resolve(3); // 异步逻辑先将结果存在临时变量,resolve返回临时结果,不要直接修改原array const p2 = new Promise((resolve, reject) => { setTimeout(() => { const tempArr = [1,2,3] resolve(tempArr) }, 2000); }); const p3 = new Promise((resolve, reject) => { setTimeout(() => { reject("foo"); }, 2000); }); const [a, tempArr, c] = await Promise.all([p1, p2, p3]) // 全部Promise执行成功后,再修改原变量 array.push(...tempArr) console.log(a, tempArr, c) } catch (err) { console.log({array}) // 此时array仍为空,符合预期 console.log({err}) } } exports.myFunction()
Mongo业务场景解决方案
你的Mongo操作场景本质是需要实现多操作的原子性,直接使用MongoDB自带的事务特性即可,无需自己实现回滚逻辑,代码示例如下:
// 开启会话 const session = await User.startSession() // 启动事务 session.startTransaction() try { const [updateRes, aggregateRes] = await Promise.all([ // 所有操作都绑定当前事务会话 User.updateOne( { _id: id }, { $set: { isDone: true }}, { session } ), Notification.aggregate([/* 你的聚合逻辑 */], { session }) ]) // 全部操作成功,提交事务 await session.commitTransaction() } catch (err) { // 任意操作报错,回滚事务,之前的update操作会被撤销 await session.abortTransaction() console.error('操作失败,已回滚所有修改:', err) } finally { // 关闭会话 await session.endSession() }
注意事项:MongoDB 4.0及以上版本才支持事务,且需要运行在副本集或分片集群模式下,本地单节点开发时需要配置单节点副本集才能正常使用事务。
内容的提问来源于stack exchange,提问作者Profer
相关产品推荐
相关产品推荐

