Async/Await嵌套问题:异步调用序列执行与返回值异常排查
问题分析与解决方案
不可修改的异步函数
有三个无法修改的异步函数:
async asyncCall1({ caseId }: { caseId: string }) { const response = await this.apolloClient.query({...}) return { ...response, data: caseResponse, }; } async asyncCall2({ caseIdFromCall1 }: { caseIdFromCall1: string }) { const response = await this.apolloClient.query({...}) return { ...response, data: caseResponse, }; } async asyncCall3({ caseIdFromCall3 }: { caseIdFromCall3: string }) { const response = await this.apolloClient.query({...}) return { ...response, data: caseResponse, }; }
需求
- 三个函数顺序执行:用asyncCall1返回结果的指定字段作为asyncCall2的入参,再用asyncCall2返回结果的指定字段作为asyncCall3的入参;
- 收集三个调用结果的指定字段到列表,最终根据列表是否包含输入值返回布尔值;
- 任意调用出错时返回指定布尔值;
- 避免异步嵌套地狱。
现有实现及问题
编写的checkAuthorization函数如下:
const checkAuthorization = (input: string) => { let coalate = [] dependency1.asyncCall1({ caseId: input }) .then((call1RawResult) => { console.log("Inside caseResult: ", call1Result); return { data: call1Result.data.caseProperties.caseId1 }; //要传给asyncCall2的字段 }) .then((call1SpecificField) => dependency2.asyncCall2({caseId: call1SpecificField.data})) .then((call2RawResult) => { const caseId2 = call2RawResult.data.caseProperties.caseId2; coalate.push(caseId2); //添加到列表 return { data: caseId2 } //传给asyncCall3的字段 }) .then((call2SpecificField) => dependency3.asyncCall3({caseId: call2SpecificField.data})) .then((call3RawResult) => { const caseId3 = call3RawResult.data.caseProperties.caseId2; coalate.push(caseId3); //添加到列表 //返回列表是否包含输入值的布尔值 return coalate.includes(input); }).catch((error) => { //任意调用出错时返回false console.log(error) return false; }) }
遇到的问题:
- 仅执行第一个
then块的日志语句,后续逻辑无响应; - 调用
checkAuthorization()时无法获取预期布尔值,返回undefined。
问题根源
- 变量名错误:第一个
then块参数是call1RawResult,但代码里用了未定义的call1Result,直接抛出异常进入catch; - 未返回Promise:
checkAuthorization没有返回then链的Promise,调用时无法获取异步结果,返回undefined; - 入参不匹配:
asyncCall2入参是caseIdFromCall1、asyncCall3入参是caseIdFromCall3,但代码里统一传了caseId,导致调用失败; - 字段收集遗漏:需求要收集三个调用的指定字段,但现有代码只收集了call2和call3的,漏掉了call1的
caseId1; - 字段取值错误:call3的字段误取成
caseId2,不符合逻辑。
优化后的实现
用async/await重构,逻辑更清晰,解决所有问题:
const checkAuthorization = async (input: string): Promise<boolean> => { const collectedIds: string[] = []; try { // 第一个异步调用:收集字段并获取下一个入参 const call1Result = await dependency1.asyncCall1({ caseId: input }); const caseId1 = call1Result.data.caseProperties.caseId1; collectedIds.push(caseId1); // 第二个异步调用:收集字段并获取下一个入参 const call2Result = await dependency2.asyncCall2({ caseIdFromCall1: caseId1 }); const caseId2 = call2Result.data.caseProperties.caseId2; collectedIds.push(caseId2); // 第三个异步调用:收集字段 const call3Result = await dependency3.asyncCall3({ caseIdFromCall3: caseId2 }); const caseId3 = call3Result.data.caseProperties.caseId3; collectedIds.push(caseId3); // 判断输入值是否在收集列表中 return collectedIds.includes(input); } catch (error) { console.error('Authorization check failed:', error); // 任意步骤出错返回false return false; } };
优化点说明
- async/await替代回调链:彻底避免嵌套,代码逻辑线性可读;
- 修正变量与入参:修复变量名错误,匹配异步函数的入参字段;
- 完整收集字段:将三个调用的指定字段全部加入列表;
- 明确返回类型:函数标记为
async,返回Promise<boolean>,调用时可通过await或.then()获取结果; - 统一错误处理:所有异步异常在
try/catch中捕获,统一返回false; - 修正字段取值:将call3的字段修正为
caseId3(若实际字段名不同可自行调整)。
使用示例
// 方式1:在async函数中用await const isAuthorized = await checkAuthorization('target-case-id'); // 方式2:用then链式调用 checkAuthorization('target-case-id').then(isAuthorized => { console.log('Authorization status:', isAuthorized); });
内容的提问来源于stack exchange,提问作者ababuji
相关产品推荐
相关产品推荐

