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

Angular中subscribe后如何正确推送返回数据到数组构建树形结构

目标树形结构

我需要生成如下格式的嵌套树形数据:

[{
 number: 3,
 children: [{
    number: 6,
    children: [{
      number: 8,
      children: []
    }]
  }, {
    number: 7,
    children: [{
      number: 9,
      children: [{
        number: 8,
        children: []
      }]
    }]
  }, {
    number: 8,
    children: []
  }, {
    number: 9,
    children: [{
      number: 8,
      children: []
    }]
  }]
}];
当前问题代码

我目前编写的实现逻辑如下:

result.subscribe((x) => {
  this.phonebookTreeModel.items = {};
  this.phonebookTreeModel.items.children = [];
  let array: any[] = [];
  x.items.forEach((item) => {
    console.log('items', item);
    if (item.parentId == 0 || item.parentId == null) {
      this.childrenArray = x.items.filter((i) => i.parentId == item.id);
      this.phonebookTreeModel.items.created = item.created;
      this.phonebookTreeModel.items.id = item.id;
      this.phonebookTreeModel.items.name = item.name;
      this.phonebookTreeModel.items.parentId = item.parentId;
      if (this.childrenArray.length > 0) {
        this.childrenArray.forEach((child) => {
          this.phonebookTreeModel.items.children.push(child);
        });
      }
      array.push(this.phonebookTreeModel);
    }
  });
  console.log('array is', array);
});

接口返回的是扁平数组,每一项都带parentId字段标识父级ID。运行后最终生成的数组里重复存入了最后一项数据,执行结果参考截图:
执行结果截图

接口返回的原始数据结构参考截图:
原始数据结构截图

我最初以为是subscribe的异步特性导致的问题,但我不希望这段逻辑异步执行,该怎么解决?

问题根因

这个问题和异步特性完全无关,核心原因有两个:

  • JavaScript中对象是引用类型,你在循环里全程修改的是同一个this.phonebookTreeModel对象,push到数组里的都是这个对象的引用,后续循环修改对象属性时,之前存入数组的元素也会同步变化,最终所有元素都会显示最后一次循环赋值的内容
  • 现有实现只处理了两层节点结构,无法生成你需要的多层嵌套树形结构
修复方案

不需要强行修改RxJS的异步逻辑,subscribe回调本身就是拿到接口返回数据后同步执行的,只需要解决对象引用问题、补全递归嵌套逻辑即可:

result.subscribe((x) => {
  const sourceList = x.items;
  // 递归生成任意层级树结构
  const buildTree = (parentIdValue: number | null) => {
    return sourceList
      .filter(item => item.parentId == parentIdValue)
      .map(item => ({
        ...item, // 拷贝当前项所有属性,生成独立新对象避免引用污染
        children: buildTree(item.id) // 递归查询当前节点的子级
      }))
  }
  // 兼容parentId为0和null两种根节点场景
  const rootNodesForZeroId = buildTree(0);
  const rootNodesForNullId = buildTree(null);
  const finalTree = [...rootNodesForZeroId, ...rootNodesForNullId];
  
  console.log('生成的树结构', finalTree);
  this.phonebookTreeModel.items = finalTree;
});

实现说明

  • 每次生成节点时都通过对象展开语法创建了独立的新对象,不存在复用同一个对象引用的问题,不会再出现所有项都是最后一条数据的情况
  • 递归逻辑自动处理任意深度的节点嵌套,不需要手动编写多层循环查询子节点,生成的结构完全匹配你的目标格式
  • 所有树结构生成逻辑都在拿到接口数据后同步执行,不存在异步时序问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 17:06:28