函数内数组非空但API返回空响应的原因及解决方法
问题原因与修复方案
问题原因
- 核心问题是异步操作未等待完成就返回结果:你在
userData?.selectedTrustees.map()中使用了async回调函数,map会立即返回一组Promise对象,但后续的console.log("response after", responseData)和res.json()并没有等待这些Promise执行完毕就直接运行了。 - 内部的
console.log能输出数据,是因为它处于异步回调的末尾,要等当前迭代里的User.findOne、Locations.findOne等异步操作完成后才会执行;而外部的代码逻辑不等待这些异步任务,所以返回时responseData还是初始的空数组。 - 额外问题:代码同时混用了
async/await和.then(),容易导致逻辑混乱,也加重了异步时序的问题。
修复步骤
- 用
Promise.all()替代直接遍历map,因为Promise.all()会等待所有异步Promise执行完成后,再返回所有结果的数组。 - 让每个异步回调返回需要添加的对象,不再直接修改外部的
responseData,最后通过Promise.all()的结果直接赋值给responseData。 - 统一使用
async/await语法,去掉.then()嵌套,让代码逻辑更清晰。
修复后的代码
exports.getUserLocation = asyncHandler(async (req, res, next) => { const phone = req.params.phone; const userData = await User.findOne({ phone }); if (!userData?.selectedTrustees) { return res.status(200).json({ success: true, response: [] }); } // 用Promise.all等待所有异步操作完成 const responseData = await Promise.all(userData.selectedTrustees.map(async (trustee) => { const data = await User.findOne({ phone: trustee.phone }); if (!data) { // 可根据需求处理找不到受托人的情况,这里返回null后续过滤 return null; } const locations = await Locations.findOne({ createdBy: trustee.phone }); if (!locations) { return next( new ErrorResponse( `User with phone ${trustee.phone} doesn't have any location stored` ) ); } const locationHistoric = locations?.locationHistoric; const lastLocation = locationHistoric[locationHistoric.length - 1]; if (trustee.sharedLocation === "true") { return { fullName: data?.fullName, id: data?._id, currentLocation: data?.currentLocation?.location, phone: data?.phone, status: data?.currentLocation?.status, createdAt: data?.currentLocation?.createdAt, share: "true", }; } else { return { fullName: data?.fullName, id: data?._id, currentLocation: lastLocation?.location, phone: data?.phone, status: data?.currentLocation?.status, createdAt: lastLocation?.createdAt, share: "false", }; } })); // 过滤掉可能的null值(比如找不到受托人的情况) const filteredData = responseData.filter(item => item !== null); console.log("response after", filteredData); res.status(200).json({ success: true, response: filteredData, }); });
额外说明
- 新增了
userData?.selectedTrustees的判断,避免无受托人时出现逻辑错误。 - 修正了错误提示的目标对象,把原代码的
${phone}改为${trustee.phone},确保错误信息指向当前遍历的受托人。 - 新增
filteredData过滤无效的null值,避免返回无效数据。
内容的提问来源于stack exchange,提问作者bill2
相关产品推荐
相关产品推荐

