JavaScript构建产品过滤函数时Promise.all未收集到Promise问题求助
我正在构建一个产品过滤函数,传入的城市(Cities)和分类(Categories)参数格式为['New York']、['Cars'],需要遍历这些参数查询对应城市或分类的产品,最终汇总结果返回给用户。
当前遇到的问题:在async回调里用console.log能看到查询到的产品,但把结果push到promises数组后,调用Promise.all时这个数组是空的,导致无法返回结果。我原本想把Promise收集到promises数组,通过Promise.all等全部解析后汇总产品,但promises始终为空。
使用MongoDB和Mongoose做产品查询,.find方法能返回匹配的产品数据,相关代码如下:
import { Product } from "../../models"; import { Response } from "../../utils"; export default async function ProductsFilters(req, res) { try { const { Cities, Categories } = req.body; let products = []; let promises = []; if (Cities.length > 0) { Cities.map(async (city) => { const results = await Product.find({ City: city }); return promises.push(results); }); } if (Categories.length > 0) { Categories.map(async (category) => { const results = await Product.find({ Category: category }); return promises.push(results); }); } const results = await Promise.all(promises); results.map((result) => products.push(result)); if (products.length > 0) Response( res, 200, true, "Të gjitha produktet u morën me sukses.", products); else Response(res, 404, false, "Asnjë produkt nuk u gjet në platformë.", null); } catch (error) { Response( res, 500, false, "Gabim i brendshëm i serverit gjatë gjetjes së produkteve.", null); } }
问题根源
你在map遍历Cities和Categories时用了async回调,map会立刻返回一个Promise数组,但你没把这些Promise存到promises里,反而在回调内部await查询结果后再push(此时push的是查询结果,不是Promise)。而且因为async回调是异步执行的,当代码走到Promise.all(promises)这一行时,所有push操作还没跑完,所以promises数组是空的。
修正方案
直接把Product.find返回的Promise收集到promises数组里,不用在map回调里await,等所有Promise都收集完再用Promise.all等待执行完成,最后合并结果。另外可以根据需求给产品去重(避免同一个产品被城市和分类查询同时命中)。
修正后的代码:
import { Product } from "../../models"; import { Response } from "../../utils"; export default async function ProductsFilters(req, res) { try { const { Cities, Categories } = req.body; const promises = []; // 收集城市查询的Promise if (Cities.length > 0) { Cities.forEach(city => { promises.push(Product.find({ City: city })); }); } // 收集分类查询的Promise if (Categories.length > 0) { Categories.forEach(category => { promises.push(Product.find({ Category: category })); }); } // 等待所有查询完成 const results = await Promise.all(promises); // 扁平化结果数组(每个find返回的是数组,flat把嵌套数组展开) const products = results.flat(); // 可选:去重,用_id作为唯一标识 // const uniqueProducts = [...new Map(products.map(item => [item._id, item])).values()]; if (products.length > 0) { Response(res, 200, true, "所有产品获取成功。", products); } else { Response(res, 404, false, "平台上未找到任何产品。", null); } } catch (error) { Response(res, 500, false, "服务器内部错误,获取产品失败。", null); } }
额外优化建议
用MongoDB的$in操作符可以减少查询次数,提升性能。比如不需要循环每个城市单独查,直接一次查询匹配所有城市:
if (Cities.length > 0) { promises.push(Product.find({ City: { $in: Cities } })); } if (Categories.length > 0) { promises.push(Product.find({ Category: { $in: Categories } })); }
这样不管有多少个城市或分类,都只需要各发起一次数据库查询,比循环查询效率高很多。
内容的提问来源于stack exchange,提问作者nevoni3008

