You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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);
    }
}

关键改动说明

  1. 简化冗余变量,优化代码结构;
  2. 用for...of替代reduce,确保每次异步操作完成后再进行下一次迭代,避免Promise堆积;
  3. 调整结果收集逻辑:初始数组先加入当前节点ID,递归将所有子节点ID依次加入,最终得到[06, 07, 08]的结果;
  4. 移除不必要的include配置(仅需子节点ID时无需关联查询整个对象,可提升查询性能)。

如果需要保留完整文档对象而非仅ID,只需把array.push(child.id)改为array.push(child)即可。

内容的提问来源于stack exchange,提问作者tonymx227

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:34:58