含Promise的async函数重构疑问:是否必须保留new Promise?
问题根源与修复方案
核心问题是:你修改后的doSomething函数没有返回一个能追踪异步操作完成状态的Promise,导致await后拿到undefined。
为什么会这样?
原代码里的new Promise是用来把Room.aggregatePaginate这个回调式异步API转换成Promise风格的——因为这个API不会返回Promise,只能通过传入回调函数获取结果。当你把new Promise去掉后:
doSomething作为async函数,执行到Room.aggregatePaginate(...)这一行就会继续往下走,直接结束函数,默认返回undefined(因为你没写return语句)。- 回调函数里的
return {...}只是回调自己的返回值,和外层的doSomething函数的返回值完全没关系,外层函数根本拿不到这个结果。
正确的修改方式
你需要保留对回调API的Promise包装,但可以优化写法(原代码里new Promise的executor用async是多余的,还会导致错误无法被reject捕获),正确的写法如下:
async function doSomething(userId) { const query = 'my-query'; const roomAggregate = Room.aggregate(query).allowDiskUse(true); // 把回调式API包装成Promise,这一步是必须的 const data = await new Promise((resolve, reject) => { Room.aggregatePaginate(roomAggregate, (err, data) => { if (err || !data) { reject(err); // 用reject传递错误,而不是throw } else { resolve(data); } }); }); // 处理数据逻辑 const rooms = []; for (let room of data.docs) { const roomId = room._id; room = await computeAThing(room, { loadWriteUps: false, loadCreators: false, }); room.userCompleted = await computeBThing(userId, roomId); rooms.push(room); } // 直接返回结果,async函数会自动把它包装成Promise return { rooms, success: true, paginator: { // 分页相关数据 }, }; }
额外说明
- 原代码里的
new Promise(async (resolve, reject) => { ... })是错误的写法:executor函数用async的话,里面的throw不会被Promise的reject捕获,应该直接用普通函数,遇到错误调用reject(err)。 - async函数的作用是让你可以用
await语法,但它不能自动把回调式API转换成Promise——对于这类老的回调API,你还是需要手动用new Promise包装,或者用工具函数(比如util.promisify)。
内容的提问来源于stack exchange,提问作者Leo Messi
相关产品推荐
相关产品推荐

