使用JavaScript reduce()结合Promise处理自关联数据库数据遇问题
使用reduce结合Promise获取自关联数据时出现Pending Promise异常
数据表结构
documentation表数据如下:
id documentationId 01 null 02 01 03 01 04 03 05 03 06 null 07 06 08 07
我的代码
async function doUpWithAssociationItSelf(id) { var arrayOfIds = [], arrayOfOtherIds = [], findedDocumentation = await DocumentationModel.findOne({ where: { id } }), array = []; arrayOfIds.push(findedDocumentation.id); arrayOfOtherIds = await getChildOfItem(array, findedDocumentation.id); console.log(arrayOfOtherIds); } async function getChildOfItem(array, id) { var childDocumentations = await DocumentationModel.findAll({ where: { documentationId: id }, include: [{ model: DocumentationModel }], order: [['position', 'ASC']] }); return childDocumentations.reduce(async pushInArray, array); } async function pushInArray(array, childDocumentation) { console.log(array); var childArray = await getChildOfItem(array, childDocumentation.id); array.push(childDocumentation.id); array.push(childArray); return array; }
核心目标
调用doUpWithAssociationItSelf("06")时,获取包含06、07、08的完整关联数据列表。
遇到的问题
控制台输出大量Promise { <pending> }和空数组:
[] Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> } Promise { <pending> }
问题原因
reduce本身不支持异步回调,当把async函数作为reduce的回调时,每次迭代返回的都是Promise对象而非数组。后续迭代的累加器参数会变成pending状态的Promise,而非预期的数组,导致逻辑混乱,最终输出一堆未解析的Promise。
解决方案
避免在reduce中使用异步回调,改用for...of循环处理异步逻辑(可读性更高,不易出错),以下是修正后的代码:
修正后的代码
async function doUpWithAssociationItSelf(id) { const findedDocumentation = await DocumentationModel.findOne({ where: { id } }); // 初始化数组,先加入当前节点ID const result = [findedDocumentation.id]; // 递归获取所有子节点并加入结果 await getChildOfItem(result, findedDocumentation.id); console.log(result); } async function getChildOfItem(array, id) { const childDocumentations = await DocumentationModel.findAll({ where: { documentationId: id }, order: [['position', 'ASC']] }); // 用for...of遍历,逐个处理异步逻辑 for (const child of childDocumentations) { array.push(child.id); // 递归获取当前子节点的子节点 await getChildOfItem(array, child.id); } }
关键改动说明
- 简化冗余变量,优化代码结构;
- 用
for...of替代reduce,确保每次异步操作完成后再进行下一次迭代,避免Promise堆积; - 调整结果收集逻辑:初始数组先加入当前节点ID,递归将所有子节点ID依次加入,最终得到
[06, 07, 08]的结果; - 移除不必要的
include配置(仅需子节点ID时无需关联查询整个对象,可提升查询性能)。
如果需要保留完整文档对象而非仅ID,只需把array.push(child.id)改为array.push(child)即可。
内容的提问来源于stack exchange,提问作者tonymx227
相关产品推荐
相关产品推荐

