JavaScript递归异步函数执行顺序问题及解决方案
异步递归获取树形工作项数据时,await未等待所有递归完成的问题解决
问题场景
我需要从文件服务器获取工作项的完整树形结构数据,用全局变量workItems存储结果。写了两个异步函数:updateChartData负责触发数据更新,buildChartData带递归逻辑用来逐层拉取节点信息,但遇到了问题:明明声明了异步函数并使用了await,程序却会提前结束等待,导致updateChartData打印的workItems不完整。递归次数不确定,没法用固定延迟解决,尝试过返回Promise但首次递归后就直接resolve,setTimeout也不起作用。
原代码实现
updateChartData函数
async function updateChartData(){ console.log("Updating chart with ID", 1); await buildChartData(1).then( console.log(workItems) ) }
buildChartData函数
async function buildChartData(currentID){ axios.get(`http://localhost:8888/_wit/workItems?id=${currentID}`).then(function(res){ let currentItem = res.data.value[0] console.log(currentItem) // 查找子项 let childItemIds = [] for (let link in currentItem.Links){ let currentLink = currentItem.Links[link] childItemIds.push([currentLink.TargetWorkItemId]) console.log("Found Child",currentLink.TargetWorkItemId) }; workItems[currentItem.WorkItemId] = { 'Title':currentItem.Title, 'WorkItemType':currentItem.WorkItemType, 'State':currentItem.State, 'Links': childItemIds }; // 递归拉取子项 if (currentItem.Links.length >0){ childItemIds.forEach(buildChartData) }; }); };
问题根源
buildChartData内部用了.then()处理axios请求,但没有返回这个Promise,也没用await等待请求完成,导致函数会直接返回一个空的已resolve状态Promise,外层的await根本等不到请求结束。- 递归时用
forEach调用异步函数,forEach不支持异步等待,所有递归请求会同时触发,父函数不会等所有子递归完成就结束。 updateChartData里的.then(console.log(workItems))写法错误,这里会立即执行console.log,而不是等buildChartData完成后再执行。
修复后的代码
通过在异步请求和递归循环中都使用await,确保所有异步操作和递归任务都完成后,再继续执行后续逻辑。
修改后的buildChartData函数
async function buildChartData(currentID){ const res = await axios.get(`http://localhost:8888/_wit/workItems?id=${currentID}`) let currentItem = res.data.value[0] console.log(currentItem) // 查找子项 let childItemIds = [] for (let link in currentItem.Links){ let currentLink = currentItem.Links[link] childItemIds.push([currentLink.TargetWorkItemId]) console.log("Found Child",currentLink.TargetWorkItemId) }; workItems[currentItem.WorkItemId] = { 'Title':currentItem.Title, 'WorkItemType':currentItem.WorkItemType, 'State':currentItem.State, 'Links': childItemIds }; // 递归拉取子项,用for await确保逐个等待完成 if (currentItem.Links.length >0){ for await (const childId of childItemIds){ await buildChartData(childId) }; }; }
修改后的updateChartData函数
async function updateChartData(){ console.log("Updating chart with ID", state.trackedID); await buildChartData(state.trackedID) console.log(workItems) }
修复说明
- 用
await axios.get()替代.then(),确保函数等待请求完成后再执行后续逻辑,同时函数会自动返回请求对应的Promise,让外层await能正确等待。 - 把递归调用的
forEach改成for await...of循环,逐个等待每个子项的递归任务完成,保证整个树形结构的数据都拉取完毕。 - 去掉
updateChartData中错误的.then()写法,直接在await之后打印workItems,确保此时数据已经完整。
内容的提问来源于stack exchange,提问作者MLancaster
相关产品推荐
相关产品推荐

