Node.js 使用Promise.all处理批量数组查询 如何获取并整理结果
实现核心逻辑
- 只要保证生成的Promise数组元素顺序和原title数组的元素顺序严格一一对应,
Promise.all返回的结果数组会严格按照传入的Promise顺序排列,和每个Promise的实际完成时间无关,不需要额外做id匹配就能对齐原数组下标,直接取值组装结果即可。
具体实现步骤
- 顺序生成双查询Promise队列
直接遍历原title数组,为每个下标位置的m_id分别绑定两个独立的查询Promise,不要在遍历逻辑里提前await异步查询,避免异步执行打乱数组push顺序。优先推荐的写法(无顺序错位风险):
const { Op } = require('sequelize') // 原title数组,每个元素包含m_id、标题等业务字段 const titleList = [] // map方法直接返回Promise本身,生成的数组顺序和原titleList完全一致 const totalVillageCountPromises = titleList.map(item => Village.count({ where: { m_id: item.m_id } }) ) const nonEmptyDateStartPromises = titleList.map(item => Village.count({ where: { m_id: item.m_id, date_start: { [Op.ne]: null } // 匹配date_start非空的统计逻辑 } }) ) - 批量执行查询并按顺序接收结果
用Promise.all同时执行两个查询队列,拿到的两个返回结果数组,每个下标位置的结果都对应原title数组同下标的m_id查询值:// 并行执行所有查询,避免串行等待拖慢整体性能 const [totalCountRes, nonEmptyRes] = await Promise.all([ Promise.all(totalVillageCountPromises), Promise.all(nonEmptyDateStartPromises) ]) - 对齐下标组装目标数组
遍历原title数组,按下标把查询结果和原数组项合并,直接推入目标数组即可:const targetResultList = titleList.map((item, index) => ({ ...item, villageTotalCount: totalCountRes[index], villageDateStartNonNullCount: nonEmptyRes[index] }))
常见坑规避
- 不要在map的async回调里手动push Promise到外部数组:由于map是同步执行的,async回调的内部异步逻辑执行时机不固定,会导致push到外部数组的Promise顺序完全错乱,最终结果和原title项错位。
- 大数量场景兜底方案:如果单批查询的条目数较多,担心极端场景下的顺序错位风险,可以让每个查询Promise的resolve结果携带对应的m_id,返回结果后先转成以m_id为key的映射对象,组装结果时直接按m_id取值,完全不依赖下标顺序:
// 带m_id的Promise生成逻辑 const totalCountPromises = titleList.map(item => Village.count({where:{m_id:item.m_id}}).then(count => ({ m_id: item.m_id, count })) ) // 结果返回后转成映射表 const totalCountMap = Object.fromEntries(totalCountRes.map(i => [i.m_id, i.count]))
内容的提问来源于stack exchange,提问作者김성준
相关产品推荐
相关产品推荐

