angular - 等待多个请求完成的正确方法是什么?
问题描述
我有一个组件需要多个 get 请求才能返回我需要的所有数据。这些是相互独立的,但我想一起进行所有调用并在成功完成后加载 UI。
为了实现这一点,我使用了 forkJoin,但我是 RxJS 的新手,我并不完全肯定我这样做是正确的。请看我下面的例子。任何帮助将不胜感激。
import { Component, Input, OnInit, ElementRef, ViewChild } from '@angular/core';
import { Observable, forkJoin, of } from 'rxjs';
import { flatMap } from 'rxjs/operators';
import { DataService, ItemGroupDto} from 'src/app/shared/services/data-service.service';
import { UserService} from 'src/app/shared/services/user-service.service';
@Component({
selector: 'app-sample',
templateUrl: './sample.component.html',
styleUrls: ['./sample.component.less']
})
export class SampleComponent implements OnInit {
@Input() itemGroupId: number;
public datasetOne: Observable<any[]>;
public datasetTwo: Observable<any[]>;
public currentApprover: string;
constructor(
private _dateService: DateService,
private _userService: UserService,
) {}
ngOnInit() {
this.getData();
}
private _getApprover(itemGroupId: number) : Observable<ItemGroupDto> {
const approver = this._userService.getApprover(itemGroupId);
approver.subscribe(results => {
const approver = results.approvers.find(approver => (
approver.Id === 1
));
this.currentApprover = approver.UserFullName;
})
return approver;
}
private _sampleDatasetOne() : Observable<any>{
const sampleDatasetOne = this._dataService.sampleDatasetOne();
sampleDatasetOne.subscribe(results => {
this.datasetOne = results;
})
return sampleDatasetOne;
}
private _sampleDatasetTwo() : Observable<any>{
const sampleDatasetTwo = this._dataService.sampleDatasetTwo();
sampleDatasetTwo.subscribe(results => {
this.datasetTwo = results;
})
return sampleDatasetTwo;
}
getData() {
let sampleDatasetOne = this._sampleDatasetTwo();
let sampleDatasetTwo = this._sampleDatasetTwo();
let approver = this._getApprover(this.itemGroupId);
forkJoin(sampleDatasetOne, sampleDatasetTwo, approver).subscribe(_ => {
// all observables have been completed
this.loaded = true;
});
}
}
上面的代码基于我在研究为此目的使用 forkJoin 时发现的一个示例。这非常适合我的要求。它允许我在他们各自的订阅中操作每个结果,然后当所有可观察对象都完成后,我可以例如通过 *ngIf 或等效方法在视图中显示数据。
但是,我也看到过如下示例:
let sampleDatasetOne = this._dataService.sampleDatasetOne();
let sampleDatasetTwo = this._dataService.sampleDatasetTwo();
let approver = this._userService.getApprover(this.itemGroupId);
forkJoin([sampleDatasetOne, sampleDatasetTwo, approver]).subscribe(results => {
this.datasetOne = results[0];
this.datasetTwo = results[1];
const approver = results[2].approvers.find(approver => (
approver.Id === 1
));
this.currentApprover = approver.UserFullName;
});
实际上,我在解释 forkJoin 的这种特殊用法的示例或在线教程中看到了很多。这似乎有点疯狂,难以阅读,维护等。但也许我只是错过了一些关键信息或概念?
本质上,我只是在寻找正确的 angular/rxJS 方式来等待多个调用完成并处理/操作每个调用的结果。
如果我走在正确的轨道上,是否有什么我遗漏、做错或可以改进的地方?
感谢任何人花时间回答并帮助我解决这个问题。
解决方案
有了一些指示,一切似乎都很好:
您要做的是创建一个服务,该服务的唯一责任是发出 http 请求并返回他们的响应。本质上是一项服务:
getMyEndpointData(): Observable<any> {
return this.http.get<any>('foo/bar/etc');
}
getMyEndpointDataById(id): Observable<any> {
return this.http.get<any>(`foo/bar/etc/${id}`);
}
// this is a good way to organize api interactions.
然后对于您的 forkJoin,我更喜欢将可观察响应分成它们自己的变量的语法:
forkJoin([this.myService.getMyEndpointData(),
this.myService.getMyEndpointDataById(1)
]).subscribe(([data, idData]: any) => {
// do stuff with data recieved
}
如果您想接受失败并仍然让其他人完成:
forkJoin([this.myService.getMyEndpointData().pipe(catchError(x => of(null))), // this deals with errors and allows other endpoints to succeed, you can do a null check in subscription code.
this.myService.getMyEndpointDataById(1)
]).subscribe(([data, idData]: any) => {
if(data) {
// do stuff with data recieved
}
}
推荐阅读
- google-bigquery - Simbda ODBC Driver BQ - 支持密钥文件路径中的变音符号
- azure - Azure Webjobs SDK:HttpTrigger。localhost 上的默认 URL 是什么?
- javascript - 映射一个类的数组以仅返回一组特定的属性
- javascript - 有没有办法制作一个按钮功能,当按下时会改变 React 中另一个组件的标题?
- c# - 如何从 Microsoft Toolkti Mvvm 包装 Messenger 和 IMessenger 以进行单元测试
- python - 为什么我必须使用 np.string_?为什么我不能使用没有下划线的 np.string?
- http - 从 Reqbin 到 BigQuery 的请求
- c# - 值类型相等和强命名程序集
- javascript - 正则表达式限制字符串不超过 5 个连续数字字符,总共不超过 8 个数字字符
- sql - 将日期列转换为另一个时区,然后按星期几分组