JavaScript中如何等待所有递归层级的API调用完成后获取生成的树结构
核心问题说明
你现有代码的问题主要有两点:
- 标注了
async的BuildTree函数没有正确返回异步操作的Promise,也没有等待递归调用的子层级执行完成,外层调用无法感知整棵树构建完成的时机 - 外层调用
BuildTree后没有等待异步流程结束就直接执行后续操作,必然拿到未填充完成的结构
改造代码
1. 修改BuildTree函数
async function BuildTree(included_files, fatherNode){ if(included_files.length <= 0) return; // 拉取当前层级所有文件的接口数据 const promises = included_files.map(item => { const url = endpoint + "file_object/" + item + "?summary=true"; return axios.get(url); }); const results = await Promise.all(promises); // 构建当前层级节点,同时收集所有子节点的构建任务Promise const childBuildPromises = results.map(response => { const node = { uid: response.data.request.uid, hid: response.data.file_object.meta_data.hid, size: response.data.file_object.meta_data.size, children: [] } fatherNode.push(node); // 返回子层级构建的Promise,用于后续统一等待 return BuildTree(response.data.file_object.meta_data.included_files, node.children); }); // 等待所有子层级递归构建完成后再返回 await Promise.all(childBuildPromises); }
2. 修改外层callFW调用逻辑
如果使用d3 v5及以上版本,d3.json本身支持Promise调用,写法更简洁:
async function callFW() { const data = await d3.json(url); Tree["uid"] = data.request.uid Tree["hid"] = data.firmware.meta_data.hid Tree["size"] = data.firmware.meta_data.size Tree["children"] = []; // 等待整棵树完全构建完成再执行后续操作 await BuildTree(data.firmware.meta_data.included_files, Tree["children"]) console.log(Tree) }
如果是旧版本d3需要用回调写法,给回调函数加async标记即可:
function callFW() { d3.json(url, async function(data) { Tree["uid"] = data.request.uid Tree["hid"] = data.firmware.meta_data.hid Tree["size"] = data.firmware.meta_data.size Tree["children"] = []; await BuildTree(data.firmware.meta_data.included_files,Tree["children"]) console.log(Tree) } }
实现原理
- 改造后的
BuildTree会将每层的异步请求、递归构建任务的Promise层层向上传递 - 最外层的
await会等待整个递归调用栈内所有异步操作全部完成后,才会执行后续的打印或其他业务逻辑 - 采用JS标准异步非阻塞方案实现等待逻辑,不会阻塞主线程其他任务的执行
内容的提问来源于stack exchange,提问作者Joe Jonah
相关产品推荐
相关产品推荐

