首页 > 解决方案 > 深度多分支树递归javascript函数未保留父引用

问题描述

我有一个数据集,其结构如下:

...
{
    "id": "id"
    "name": "name" 
    "children": ["IdToChild", "IdToChild"]
}
... And so forth 

数据最终将构建一个深度多分支树。流程如下:

  1. 从具有子引用的数据库中获取父对象
  2. 从引用中获取孩子
  3. 将子数组附加到父对象
  4. 继续 - 如果有更多子引用¨

我的目标是拥有一个结构类似于此的完整树:

{   
    "id": "myId"
    "name": "name 1",
    "children": '[
        {
            "id": "myId"
            "name": "name 2",
            "children": [
                {
                ...
                }
            ]
        },
        {
            "id": "myId"
            "name": "name 3",
            "children": [
                {
                ...
                },

            ]
        },
    ]
}

我有以下代码:

async function caller(){
    //Fetch parent object from database
    await assembletree(parentObj)
}

async function assembletree(parentObj){
    let childrenArray = []
 
    for(let index = 0; index < parentObj.children.length; index++){
        //Async call to database to get child object by id
        childrenArray.push(databaseObject)
    }
   
    //Remove existing children property that holds just the Ids
    delete parentObj.children

    //Assign the childrenArray to a new property named "children"
    Object.assign(parentObj, parentObj, {"children": childrenArray})

    //Initiate recursion to fetch next children
    for(let index = 0; index < parentObj.children.length; index++){
        await assembletree(parentObj.children[index]) // <--- 2nd child is never called
    }
}

当我有一个单一的深层分支时,上面的代码真的没有问题。但是当我在父对象中遇到多个子对象时,代码只对第一个子对象进行递归。

当我调试我的代码时,我可以看到只有第一个子对象正确触发了递归循环,但第二个子对象永远不会被处理。

当然,我不确定我错过了什么,因为一切对我来说似乎都是有效的。我对上述问题的初步猜测是,由于某种原因,引用失去了对第二个子对象的跟踪。

标签: javascript

解决方案


您的主要问题是第二个 for 循环:

for(index = 0; index < parentObj.children.length; index++){

你之前忘记了let关键字index结果是您现在正在使用index与重复调用共享的全局变量。

添加后,let您的代码似乎工作正常:

async function assembletree(parentObj){
    let childrenArray = []
 
    for(let index = 0; index < parentObj.children.length; index++){
        //Async call to database to get child object by id
        const databaseObject = await fetchDatabaseObject(parentObj.children[index]);
        childrenArray.push(databaseObject)
    }
   
    //Remove existing children property that holds just the Ids
    delete parentObj.children

    //Assign the childrenArray to a new property named "children"
    Object.assign(parentObj, parentObj, {"children": childrenArray})

    //Initiate recursion to fetch next children
    // Added the let keyword below!
    for(let index = 0; index < parentObj.children.length; index++){
        await assembletree(parentObj.children[index]) // <--- 2nd child is now called
    }
}

(async function () {
  try {
    const object = await fetchDatabaseObject(1);
    await assembletree(object);
    console.log(object);
  } catch (e) {
    console.error(e.message);
  }
})();

// mock data/database
const records = [{
  "id": 1,
  "name": "a" ,
  "children": [2, 3],
}, {
  "id": 2,
  "name": "b" ,
  "children": [4],
}, {
  "id": 3,
  "name": "c" ,
  "children": [5],
}, {
  "id": 4,
  "name": "d" ,
  "children": [],
}, {
  "id": 5,
  "name": "e" ,
  "children": [],
}];
const indexed = new Map(records.map(record => [record.id, record]));

async function fetchDatabaseObject(id) {
  await sleep(100);
  return deepDupplicate(indexed.get(id));
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function deepDupplicate(object) {
  return JSON.parse(JSON.stringify(object));
}

可以进行很多优化,但我会将这些优化排​​除在答案的重点之外。


推荐阅读