简体   繁体   English

如何在递归调用方法[ReactJS]之前等待a.forEach循环完成其异步请求?

[英]How to wait for a .forEach loop to finish its async request before calling method recursively [ReactJS]?

This program is written using ReactJS and REST API is used to get the data.该程序使用 ReactJS 和 REST 编写,API 用于获取数据。 The problem I am facing is that I am trying to traverse a tree of data and I need to make an async request for each node in the tree.我面临的问题是我正在尝试遍历数据树,并且需要为树中的每个节点发出异步请求。

The tree looks something like this: example tree树看起来像这样:示例树

Currently, my code traverses the tree in breadth-first order, and the order looks like: 1->2->3->4->4.目前,我的代码以广度优先顺序遍历树,顺序如下:1->2->3->4->4。 I need it to traverse the tree in depth-first order, so that the order is 1->3->4->2->4.我需要它以深度优先顺序遍历树,因此顺序为 1->3->4->2->4。 The goal is to make an API request for each node in depth-first order and push the results into an array.目标是以深度优先顺序为每个节点发出 API 请求,并将结果推送到数组中。

The data we start off with is an array, [node1, node2] , and the result array should be [node1, node3, node4, node2, node4] .我们开始的数据是一个数组[node1, node2] ,结果数组应该是[node1, node3, node4, node2, node4]

The issue is that the async nature of the method allows the code to move to node 2 before we've even traversed and pushed the child data for node 1 into our resulting array.问题是该方法的异步特性允许代码在我们遍历节点 1 并将其推送到我们的结果数组之前移动到节点 2。 Before we've completely traversed all possible children for node1, it's already moving on to node2 and pushing that into our result array, and then going on to process it as well.在我们完全遍历 node1 的所有可能子节点之前,它已经移动到 node2 并将其推送到我们的结果数组中,然后继续处理它。 Here is an example of what the code looks like currently:这是当前代码的示例:

var resultArray = [];

    getNodes(nodesArray) {

        nodesArray.forEach(node => {

          //Store nodes
          resultArray.push(node)

            //make a new request
            const newRequest = node.id;

            //our async request
            getNodeData(newRequest)

                .then((data) => {
                  var childNodes = data.nodes;

                  //Call method again for child nodes
                  this.getNodes(childNodes);
                    

                })
                .catch((error) => {
                    console.log(error)
                })
        })
    }

I have tried using Promises to await for the data to come in, but no luck in getting the.forEach loop to actually wait before moving onto the next node.我已经尝试使用 Promises 来等待数据进入,但没有运气让 .forEach 循环在移动到下一个节点之前实际等待。

You can make the function async , then use await with a for... of loop.您可以将 function 设为async ,然后将awaitfor... of循环一起使用。

async getNodes(nodesArray) {
    for (const node of nodesArray) {
        resultArray.push(node)
        const newRequest = node.id;
        try {
            const res = await getNodeData(newRequest);
            const childNodes = res.nodes;
            await this.getNodes(childNodes);
        } catch (error) {
            console.log(error);
        }
    })
}

Since getNodes makes asynchronous calls, its result will be a Promise, so you can mark the getNodes method as async .由于getNodes进行异步调用,其结果将是 Promise,因此您可以将getNodes方法标记为async

IMO getNodes should return the list of nodes rather than modifying some external array as a side-effect, so getNodes can be modified to return a Promise that resolves to the list of nodes. IMO getNodes应该返回节点列表而不是修改某些外部数组作为副作用,因此可以修改getNodes以返回解析为节点列表的 Promise。

With a for-loop in an async function, you can take advantage of await for both your getNodeData async function call, and the getNodes recursive call.通过异步 function 中的 for 循环,您可以在getNodeData异步 function 调用和getNodes递归调用中利用await

// returns a Promise that resolves to a list of nodes
async getNodes(nodesArray) {
  const resultArray = [];
  for (const node of nodesArray) {
    // Store nodes
    resultArray.push(node);

    // make a new request
    const newRequest = node.id;

    //our async request
    try {
      const data = await getNodeData(newRequest);
 
      // call method again for child nodes
      resultsArray.concat(await this.getNodes(childNodes)); 
    } catch (error) {
      console.error(error);
    }    
  }
  return resultsArray;
}

Promise.all will help here, turning an array of Promises into a Promise for an array of values. Promise.all将在这里提供帮助,将 Promise 数组转换为 Promise 以获取值数组。 We can use this together with a recursive call for the children, combining the parent and children into a single array, and then flattening the result.我们可以将它与对子项的递归调用一起使用,将父项和子项组合成一个数组,然后将结果展平。 Something like this should do it:这样的事情应该这样做:

 const getNodes = (nodes) => Promise.all ( nodes.map (node => getNodeData (node).then (parent => getNodes (parent.nodes).then (children => [parent, ...children])) ) ).then (nodes => nodes.flat()) getNodes ([1, 2]).then (console.log).catch (err => console.log (`Error: ${err}`))
 .as-console-wrapper {max-height: 100%;important: top: 0}
 <script> /* dummy implementation of getNodeData */ const getNodeData = ((data = {1: {id: 1, x: 'foo', nodes: [3, 4]}, 2: {id: 2, x: 'bar', nodes: [4]}, 3: {id: 3, x: 'baz', nodes: []}, 4: {id: 4, x: 'qux', nodes: []}} ) => (id) => new Promise ((res, rej) => setTimeout(() => data[id]? res(JSON.parse(JSON.stringify(data[id]))): rej(`${id} not found`)), 100) )() </script>

getNodeData is a dummy implementation, just meant to return a quick Promise for your data by id. getNodeData是一个虚拟实现,只是为了通过 id 为您的数据返回一个快速的 Promise。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在另一个异步 function 中执行代码之前,如何在异步 function 中等待循环完成? - How to wait for a loop to finish in an async function before executing code in another async function? 等待异步方法完成 - Wait for async method to finish 在调用异步 function 之前等待提交事件完成 - Wait for a submit event to finish before calling async function 如何等待异步查询在 for 循环中完成? - How to wait for an async query to finish in a for loop? NodeJS:如何在继续执行代码之前等待异步请求的 for 循环完成? - NodeJS: How to wait for a for-loop of async requests to finish before proceeding with code? 在forEach循环中调用服务并等待其完成,然后继续操作 - Calling a service within a forEach loop and waiting for it to finish before proceding .then 在调用下一个方法之前是否等待 setState 完成? - Does .then wait for setState to finish before calling the next method? 如何在从我的 promise / function 返回之前等待 forEach 完成 - How to wait for a forEach to finish before returning from my promise / function 如何在继续测试之前等待 Vue 组件的异步安装完成 - How to wait for async mounted of Vue component to finish before continuing with testing 如何在继续async.series之前等待findOneAndUpdate完成 - How to wait for findOneAndUpdate to finish before continuing async.series
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM