首页 > 解决方案 > 等到所有 Observables 完成

问题描述

我的代码中很少有像这样的 Observable。

this.server.doRequest().subscribe(response => console.log(response)
      error => console.log(error),
      () => {
        console.log('completed');
      });

这些 Observable 可能有任意数量,因此我需要编写一个函数来检查每个 Observable 是否已完成,否则会等到每个 Observable 完成。

我假设我可以创建一个数组,在那里推送每个新的 Observable,并在完成后按索引将其删除。但这是好的解决方案吗?

我想在哪里使用它。例如,我有一个页面,用户在其中异步上传任意数量的照片,然后他按下完成按钮。一旦他按下完成按钮,我需要等到所有动态创建的 Observables 完成。

标签: javascriptrxjsobservable

解决方案


您应该为此使用更高阶的可观察对象,您的确切用例将决定确切的运算符,但 forkJoin 似乎是一个不错的选择:

forkJoin(
  this.server.doRequest1(),
  this.server.doRequest2(),
  this.server.doRequest3(),
  this.server.doRequest4()
).subscribe(vals => console.log('all values', vals));

在所有内部可观察对象完成之前,forkJoin 不会发出。使其成为等待多个可观察对象完成的首选操作符。你也可以给它一个可观察的数组。还有多个其他运算符也可以满足您的情况,例如 concat、merge、combineLatest 或其他一些运算符。

根据更多细节进行编辑:

在更新中描述的用例中,您仍然希望使用更高阶的 observable,但 forkjoin 不是您想要的。您将希望使用本地主题来完成目标,因为希望在选择每个可观察对象时启动它并等待它们全部完成会使事情变得有点复杂(但不是太多):

假设你有一个像这样的模板:

<button (click)="addPhoto()">Add Photo</button>

<button (click)="finish()">Finish</button>

添加照片按钮获取用户照片和所有这些,完成是你的完成,你可以有一个这样的组件:

private addPhoto$ = new Subject();

constructor() {
  this.addPhoto$.pipe(
    mergeMap(() => this.uploadPhoto()),
  ).subscribe(
    (resp) => console.log('resp', resp),
    (err) => console.log('err', err),
    () => console.log('complete')
  );
}

private uploadPhoto() {
  // stub to simulate upload
  return timer(3000);
}

addPhoto() {
  this.addPhoto$.next();
}

finish() {
  this.addPhoto$.complete();
}

如果您运行此代码,您会看到添加的照片在完成时将在订阅处理程序中发出,但只有在所有照片上传完成并且用户单击完成后才会触发完成。

这是一个演示功能的stackblitz:

https://stackblitz.com/edit/angular-bsn6pz


推荐阅读