javascript 如何使用递归API调用构建对象树?

z9smfwbn  于 2022-11-20  发布在  Java
关注(0)|答案(1)|浏览(185)

我想构造一个树,其中每个节点都在API调用中使用以获取子节点;从根目录开始。这将递归执行,直到到达TREE_DEPTH_LIMIT

export const search = async (searchTerm) => {

  try {
    const tree = {};
    await createTree(searchTerm, tree);
    return tree;
  } catch (err: any) {}
};

const TREE_DEPTH_LIMIT = 3;

const createTree = async (searchTerm, tree) => {
  if (counter === TREE_DEPTH_LIMIT) {
    counter = 0;
    return;
  }

  counter++;

  tree[searchTerm] = {};

  try {
    const res = await axiosInstance.get(
      `/query?term=${searchTerm}`
    );

 // res.data.terms is an array of strings
    res.data.terms.forEach((term) => {
      createTree(term, tree[searchTerm]);
    });
  } catch (err) {}
};

我尝试在上面的createTree()函数中递归地执行此操作。它将在API调用中使用searchTerm。然后它将遍历res.data.terms并在每个条件上调用createTree()。但输出不是我所期望的。
输出如下:

const tree = {
  apple: {
    apple_tree: {},
    tree: {},
  },
};

预期输出:(因为TREE_DEPTH_LIMIT为3,所以树中应有3个级别)

const tree = {
  apple: {
    apple_tree: {
      leaf: {},
    },
    tree: {
      trunk: {},
    },
  },
};

还是我的解决方案完全不正确,我应该去另一种方法?

wfauudbj

wfauudbj1#

一些问题:

  • counter看起来是一个全局变量,但这样做效果不好,因为每次递归返回时,counter都应该恢复它的值。最好使用一个局部变量,这样每个执行上下文都有它自己的版本。更好的方法是将它作为一个参数,让它向下计数而不是向上计数。
  • 递归调用是不等待的,因此在search中,createTree返回的promise可能在所有子节点都被填充之前就解决了,因此您将使用一个不完整的树。
  • 这不是一个真实的的问题,但调用者必须创建一个tree对象并将其作为参数传递,这并不是最优雅的。我将重新设计函数,以便search将自己创建该对象,然后使用递归函数创建 children --因此我将该函数命名为createChildren,而不是createTree

下面是一个代码片段,它首先模拟get方法,以便您可以实际运行它:

// Mock for this demo
const axiosInstance = {async get(term) {const delay = ms => new Promise(resolve => setTimeout(resolve, ms));await delay(50);return {data: {terms: {"apple": ["apple_tree", "tree"],"apple_tree": ["leaf"],"leaf": [],"tree": ["trunk"],"trunk": []}[term.split("=")[1]]}};}}

const createChildren = async (searchTerm, depth) => {
  if (depth-- <= 0) return {};
  try {
    const res = await axiosInstance.get(`/query?term=${searchTerm}`);
    const promises = res.data.terms.map(async (term) =>
      [term, await createChildren(term, depth)]
    );
    return Object.fromEntries(await Promise.all(promises));
  } catch (err) {
    console.log(err);
  }
};

const TREE_DEPTH_LIMIT = 3;
const search = async (searchTerm, depth=TREE_DEPTH_LIMIT) =>
    ({[searchTerm]: await createChildren(searchTerm, depth)});

// Demo
search("apple").then(tree =>
    console.log(tree)
);

相关问题