递归调用MS Graph API的DFS函数为何无法等待异步执行完成
问题根因
现有代码无法直接拿到结果的核心原因是异步逻辑没有被正确等待:
start是同步函数,内部发起的callMsGraph异步请求、递归调用都没有被阻塞,函数会在所有请求发出后立刻返回空数组,此时数组还没被异步回调填充- 遍历用的
forEach不支持异步等待,即使回调内写了Promise逻辑,外层也不会等待回调执行完成 - 递归调用
start时没有返回/等待对应的Promise,外层完全无法感知递归内部的异步执行状态,只能靠固定时长的setTimeout碰运气等请求跑完。
修复后完整代码
callMsGraph工具函数不需要修改,只需要调整shelfdb.data内的递归逻辑即可:
shelfdb.data = async (accessToken) => { const token = accessToken; const endpoint = 'https://graph.microsoft.com/v1.0/sites/webgroup.sharepoint.com,23e7ef7a-a529-4dde-81ba-67afb4f44401,0fa8e0f7-1c76-4ad0-9b6e-a485f9bfd63c/drive/items/01GNYB5KPQ57RHLPZCJFE2QMVKT5U3NYY3/children' async function start(node, array) { if(node.value?.length > 0) { for (const child of node.value) { const end = 'https://graph.microsoft.com/v1.0/sites/webgroup.sharepoint.com,23e7ef7a-a529-4dde-81ba-67afb4f44401,0fa8e0f7-1c76-4ad0-9b6e-a485f9bfd63c/drive/items/' + child.id + '/children'; try { const currResult = await callMsGraph(token, end); if (currResult.value?.length > 0) { if ('image' in currResult.value[0]) { currResult.value.forEach(function(imgChild) { let img = { 'name': imgChild.name, 'job': imgChild.parentReference.path.split("/")[6], 'path': imgChild.webUrl, 'id': imgChild.id } array.push(img); }) continue; } await start(currResult, array); } } catch (e) { console.error(e.message); } } } return array; } const res = await callMsGraph(token, endpoint); const output = await start(res, []); console.log(output); return output; }
关键修改说明
- 将
start改为async函数,允许内部通过await阻塞异步流程 - 替换原
forEach循环为for...of循环:forEach不会等待异步回调执行,for...of配合await可以保证当前节点的请求、子节点递归全部执行完成后,再处理下一个同级节点,符合深度优先搜索的执行顺序 - 所有异步操作(接口请求、递归调用)都添加
await,让整个异步执行链的状态可以被外层捕获,不会提前返回空数组 - 增加可选链
?.判断,避免接口返回异常结构时抛出Cannot read properties of undefined错误 - 错误处理移入循环内部,单个节点请求失败不会中断整个遍历流程
内容的提问来源于stack exchange,提问作者TabulaRasa
相关产品推荐
相关产品推荐

