首页 > 解决方案 > 等待多个请求完成的正确方法是什么?

问题描述

我有一个组件需要多个 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 方式来等待多个调用完成并处理/操作每个调用的结果。

如果我走在正确的轨道上,是否有什么我遗漏、做错或可以改进的地方?

感谢任何人花时间回答并帮助我解决这个问题。

标签: angulartypescriptrxjsfork-join

解决方案


有了一些指示,一切似乎都很好:

您要做的是创建一个服务,该服务的唯一责任是发出 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
}
}

推荐阅读