Angular 12 基于RXJS处理多API调用时首个接口重复请求的解决方法
问题根源
默认情况下RxJS的Observable是冷流,每新增一次订阅就会重新执行上游的生产逻辑,你原代码中obs2$和obs3$分别派生自obs1$,模板的两个async管道相当于给两个派生流各做了一次订阅,最终触发了两次getData1的API请求。
解决方案
我们用shareReplay把obs1$转换成多播的热流缓存结果,再配合forkJoin并行执行两个后续请求,不需要额外的标记位即可实现需求。
所需导入依赖
import { forkJoin, Observable } from 'rxjs'; import { switchMap, shareReplay, tap } from 'rxjs/operators';
组件类代码
// 定义合并结果的成员变量 result$!: Observable<{data2: string, data3: string}>; // 移除原有的obs1$、obs2$、obs3$、flag2、flag3成员变量 private id!: string; ngOnInit(): void { this.result$ = this.getData1().pipe( // 拿到getData1的结果后并行发起两个后续请求 switchMap(() => forkJoin({ data2: this.getData2(), data3: this.getData3() })) ); } private getData1(): Observable<string> { return this.service.getData1<string>('/api/get_1').pipe( tap((response: string) => { this.id = response; }), // 多播缓存结果,多次订阅不会重复发起请求 shareReplay(1) ); } private getData2(): Observable<string> { // 移除原tap中的flag2赋值逻辑 return this.service.getData2<string>('/api/get_2/id='+this.id); } private getData3(): Observable<string> { // 移除原tap中的flag3赋值逻辑 return this.service.getData3<string>('/api/get_3/id='+this.id); }
模板代码
<ng-container *ngIf="result$ | async as data; else loading"> <sub-component [data2]="data.data2" [data3]="data.data3" ></sub-component> </ng-container> <ng-template #loading> Loading... </ng-template>
实现说明
shareReplay(1)会缓存getData1的返回结果,所有订阅这个流的地方都会复用同一份请求结果,不会重复发起API调用。forkJoin会等传入的所有Observable都完成后,才会把所有结果按传入的key合并为一个对象发出,天然满足“所有API响应全部返回后再传递数据给子组件”的需求,不需要额外的标记位做状态判断。- 全程用
async管道处理订阅和取消订阅,避免手动subscribe带来的内存泄漏风险。
内容的提问来源于stack exchange,提问作者Prabhu
相关产品推荐
相关产品推荐

