为何从Express路由调用的异步函数内for循环无法正常迭代执行?
问题原因与修复方案
核心问题梳理
循环不执行、过滤逻辑失效由以下几个错误导致:
- 循环条件错误:
currentUser.likes和currentUser.dislikes都是数组类型,直接写i < currentUser.likes相当于数值和数组对象比较,结果永远为false,所以循环根本不会触发,正确写法是取数组长度i < currentUser.likes.length - 参数传递缺失:路由中调用
filter(currentUser, user)时,没有传入res对象,导致filter函数中调用res.json会直接抛出undefined错误 - 过滤逻辑完全错误:查询得到的
user是符合性别取向的用户数组,不是单个用户,且直接拿整个likes数组和用户id对比,逻辑完全不成立,循环内部的return也会导致第一次判断就直接返回结果,不会完成全量过滤 - 异步函数未等待:
filter是async函数,调用时没有加await,如果后续加了异步逻辑会出现时序问题
修复方案
方案1:修正原有过滤逻辑
// 路由部分修改 router.get("/user/match/:id", asyncHandler(async (req, res, next) => { const currentUser = await User.findOne({ _id: req.params.id }); if ( currentUser.gender === "Male" && currentUser.sexualPreference === "Straight") { const users = await User.find({ gender: "Female", sexualPreference: "Straight"}); // 传入res参数,添加await await filter(currentUser, users, res); } })); // 过滤函数修改 const filter = async (currentUser, users, res) => { try { // 合并已点赞和已点踩的id,生成排除列表 const excludeIds = [...currentUser.likes, ...currentUser.dislikes]; // 过滤掉排除列表内的用户 const availableUsers = users.filter(user => !excludeIds.includes(user._id.toString())); if (availableUsers.length) { return res.json({ users: availableUsers }); } else { return res.json({ message: "你所在的区域暂无新用户" }); } } catch (error) { res.status(500).json(error); } };
方案2(更推荐):MongoDB查询阶段直接过滤,性能更高
直接使用MongoDB的$nin操作符在查询时就排除已点赞、已点踩的用户,不需要后端二次遍历,性能更优:
router.get("/user/match/:id", asyncHandler(async (req, res, next) => { const currentUser = await User.findOne({ _id: req.params.id }); if ( currentUser.gender === "Male" && currentUser.sexualPreference === "Straight") { const excludeIds = [...currentUser.likes, ...currentUser.dislikes]; // 查询时直接过滤不符合要求的用户 const availableUsers = await User.find({ gender: "Female", sexualPreference: "Straight", _id: { $nin: excludeIds } }); if (availableUsers.length) { return res.json({ users: availableUsers }); } else { return res.json({ message: "你所在的区域暂无新用户" }); } } }));
该方案完全不需要单独写过滤函数,代码更简洁,查询效率也更高。
内容的提问来源于stack exchange,提问作者RandyBeans
相关产品推荐
相关产品推荐

