为何map函数内使用await返回Promise、外部await可直接拿到数据
问题底层原因解析
- async函数的返回值特性
所有标记为async的函数,无论内部返回值是什么类型,最终都会自动将返回值包装为一个Promise对象。你给map传入的是async回调函数,因此每个回调执行后都会返回一个Promise,map的作用是遍历数组收集所有回调的返回值,最终得到的自然就是Promise数组。 - await的作用域限制
await只会暂停它当前所在的async函数的执行,不会影响外层函数以及其他同步逻辑的运行。
你代码中的await写在map的内部async回调里,因此只会暂停对应单个回调的执行:当遍历到某个id执行回调,遇到await User.findById(id)时,会将当前回调挂起,立刻返回一个pending状态的Promise给map,map不会等待这个Promise完成,会立刻继续遍历下一个id。
整个map遍历是同步完成的,因此外层的console.log("ARRAY GUIDE:", guideArray)会在所有数据库查询完成前就执行,打印出Promise数组。等到后续某个数据库查询完成,对应的被挂起的回调才会恢复执行,此时user已经是查询完成的实际数据,因此回调内的console.log("USER: ", user)会打印真实用户数据。
你单独查询时await是写在外层的tourSchema.post的async函数内,因此会暂停整个外层函数的执行,等查询完成才会继续往下走,所以guideSingle能直接拿到用户数据。
正确实现方式
你已知的Promise.all方案是标准处理写法:
// this.guides = ["userIdOne","userIdTwo"] tourSchema.post("save", async function (doc, next) { const guideSingle = await User.findById(this.guides[0]); const guidePromiseArray = this.guides.map(async (id) => { console.log("ID: ", id); let user = await User.findById(id); console.log("USER: ", user); return user; }); // 等待所有查询完成,拿到实际用户数据数组 const guideArray = await Promise.all(guidePromiseArray); console.log("SINGLE GUIDE: ", guideSingle); console.log("ARRAY GUIDE:", guideArray); next(); });
内容的提问来源于stack exchange,提问作者Mubasher Ali
相关产品推荐
相关产品推荐

