微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

等待多个请求完成的正确方法是什么?

如何解决等待多个请求完成的正确方法是什么?

我有一个需要多个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,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
}
}
,

您提供的代码看起来不错。为了可维护性和可读性,通常最好跟随尾随$命名可观察对象。另外,您不必维护和设置值,而只需维护一个可观察值,该值具有以您想要绑定到模板的对象格式映射的值。这样可以减少代码并使其更简洁。

在这种情况下,是这样的:

let sampleDatasetOne$ = this._dataService.sampleDatasetOne();
let sampleDatasetTwo$ = this._dataService.sampleDatasetTwo();
let approver$ = this._userService.getApprover(this.itemGroupId);

let data$ = forkJoin([sampleDatasetOne$,sampleDatasetTwo$,approver$]).pipe(map(results => ({
      dataSetOne: results[0],dataSetTwo: results[1],approver: results[2].approvers.find(approver => (
        approver.Id === 1
      ))})));

data $可以异步传递到模板中(它将订阅和取消订阅)。此外,您的映射函数可以强烈键入返回值,因此可以在模板或组件中的其他位置将其作为Observable进行检查。希望这会有所帮助。

但是在这种情况下,forkJoin似乎是合适的运算符:)

,

我会说这取决于你在做什么。

如果仅希望所有Observable都完成后再对它们的发射值进行某种处理,则可以使用一些语法糖:

forkJoin([observable1,observable2,observable3])
  // Array destructuring,a cool EcmaScript 6 feature.
  .subscribe(([value1,value2,value3]) => {
     this.value1 = value1;
     this.value2 = value2;
     this.value3 = value3
  }
);

这仍然留有可能性,可以在将可观察对象传递给forkJoin之前对其进行处理,例如:

const mappedObservable1 = observable1
  .pipe(
     map(value1 => mapToSomething(value1))
     tap(mappedValue1 => this.value1 = mappedValue1)
  );

forkJoin([mappedObservable1,observable3]).subscribe(() =>
  this.loadingDone = true;
)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。