如何并行执行更新操作
关于Promise构造器使用async回调的问题分析
嘿,我看到你发现了一个有趣的现象——当把async函数作为new Promise()的回调参数时,你的数据库查询能正常执行,并且在Promise.all([]).then()里能拿到预期结果,而用普通非async回调时可能达不到预期。咱们来拆解一下这个情况:
为什么async回调能解决你的问题?
先看你给出的示例代码片段:
const borrowersFeePromise = new Promise(async (resolve, reject) => { if (borrowersFee !== undefined && borrowersFee !== '') { const borrowersFeeUpserted = await Fees.update( { personId: mongoose.Types.ObjectId(personId), category: 'borrowersFee', }, { $set: { amount: borrowersFee } } // 猜测你可能漏了upsert选项,不过这不影响核心逻辑 ); resolve(borrowersFeeUpserted); } else { resolve(null); // 这里处理空值的情况 } });
核心原因很简单:
- 当你用
async函数作为Promise构造器的回调时,内部的await会暂停回调函数的执行,直到Fees.update()这个异步数据库操作完成,之后才会调用resolve()把最终结果传递出去。 - 而如果不用
async,直接写普通回调的话,如果你没正确处理Fees.update()的异步性(比如忘记用.then()链式调用,或者没在异步操作的回调里调用resolve),就会导致Promise提前resolve,Promise.all拿到的是还没完成的异步操作的状态,自然得不到预期结果。
但要注意:这种写法有冗余和风险!
虽然这个写法解决了你的问题,但非常不推荐把async函数直接传给Promise构造器,原因有两个:
- 冗余包装:
async函数本身就会返回一个Promise,再套一层new Promise完全是多余的,增加了不必要的嵌套。 - 错误处理隐患:如果
await的操作抛出错误,async函数会自动把它转化为rejected状态,但因为你在Promise构造器里,这个错误可能会被构造器的reject逻辑覆盖,或者如果没加try/catch的话,会导致未捕获的异常。
更优雅的替代写法
其实你完全可以去掉外层的new Promise,直接用async函数返回Promise:
// 定义一个返回Promise的async函数 const getBorrowersFeeResult = async () => { if (borrowersFee !== undefined && borrowersFee !== '') { // 直接return await的结果,async函数会自动包装成Promise return await Fees.update( { personId: mongoose.Types.ObjectId(personId), category: 'borrowersFee', }, { $set: { amount: borrowersFee } }, { upsert: true } // 加上upsert更符合常见的更新/插入场景 ); } // 空值情况直接返回null,同样会被包装成resolved的Promise return null; }; // 在Promise.all里调用这个函数 Promise.all([getBorrowersFeeResult()]) .then(results => { // 这里就能拿到预期的更新结果了 console.log(results); }) .catch(err => { // 统一捕获所有异步操作的错误 console.error(err); });
这样既保持了代码的简洁性,又避免了冗余的Promise包装,同时错误处理也更清晰——如果Fees.update()出错,会直接被Promise.all的.catch()捕获,不会出现隐藏的异常。
内容的提问来源于stack exchange,提问作者Woppi
相关产品推荐
相关产品推荐

