Angular中如何使用httpClient请求返回参数循环发起同接口请求
问题原因
你遇到的问题本质是同步循环触发异步请求的执行顺序问题:getParentById返回的HttpClient请求是异步Observable,subscribe的回调函数要等网络请求完成后才会执行,而for循环是同步代码,会在所有请求实际发起前就全部执行完毕,此时this.parentId还没有被回调更新,所以所有请求都用了初始的'123'作为入参。
解决方案
下面提供3种常用的实现方式,你可以根据自己的项目习惯选择:
方案1:使用RxJS expand 操作符(推荐,符合响应式编程规范)
expand是RxJS专门用于处理「需要根据前一次请求结果发起下一次请求」的递归场景的操作符,不需要手动维护全局变量:
import { expand, take, toArray } from 'rxjs/operators'; const initialId = '123'; // 总共需要请求的次数 const totalRequest = arr.length; this.getParentById(initialId).pipe( // 递归发起下一次请求 expand((res) => this.getParentById(res.parentId)), // 取指定次数的请求结果 take(totalRequest), // 可选:将所有请求的返回结果按顺序收集为数组 toArray() ).subscribe((allNodeList) => { // 所有请求完成,此处处理返回的全量节点数据 console.log(allNodeList); });
如果不需要固定请求次数,而是查到根节点(没有父节点)就自动停止,可以把take(totalRequest)替换为takeWhile(res => !!res.parentId, true)即可。
方案2:使用async/await转为同步逻辑
如果更习惯同步写法,可以把Observable转为Promise,用await控制循环执行顺序:
async function queryAllParentNodes() { let currentId = '123'; const result = []; for (let i = 0; i < arr.length; i++) { // 等待当前请求完成再执行后续逻辑 const res = await this.getParentById(currentId).toPromise(); result.push(res); // 更新下一次请求的入参 currentId = res.parentId; } // 所有请求完成,处理结果 console.log(result); } // 启动请求 queryAllParentNodes();
方案3:使用递归函数手动控制流程
也可以自己实现递归逻辑,手动控制下一次请求的触发时机:
this.parentId = '123'; const result = []; let currentCount = 0; const getNextNode = () => { // 达到请求次数就终止递归 if (currentCount >= arr.length) { console.log(result); return; } this.getParentById(this.parentId).subscribe(res => { result.push(res); this.parentId = res.parentId; currentCount++; // 请求完成后再发起下一次 getNextNode(); }) } // 启动第一次请求 getNextNode();
注意:你提供的代码里方法定义为
getParentById,但循环调用时写的是getNodeById,请根据实际的方法名调整代码,避免出现调用错误。
内容的提问来源于stack exchange,提问作者Ziad Mohamed
相关产品推荐
相关产品推荐

