【问题标题】:Wait till all Observables are completed等到所有 Observable 完成
【发布时间】:2019-07-13 14:02:13
【问题描述】:

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

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

可以有任意数量的 Observable, 所以我需要编写一个函数来检查每个 Observable 是否完成,否则会等到每个完成。

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

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

【问题讨论】:

    标签: javascript rxjs observable


    【解决方案1】:

    您应该为此使用更高阶的 observables,您的确切用例将决定确切的运算符,但 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();
    }
    

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

    这是一个演示功能的堆栈闪电战:

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

    【讨论】:

    • doRequest1 未完成时会执行 doRequest2 吗?
    • 这是个好主意。但是 Observable 是动态创建的。例如用户点击按钮。如何使用 forkJoin 动态创建的 Observerable
    • @tgralex 与 forkJoin,所有请求并行执行。如果需要,其他运算符可以按顺序进行。
    • @NickD 很容易。你可能需要给出一个更清晰的例子来说明你所追求的
    • 我用我尝试构建的示例更新了我的问题
    【解决方案2】:

    我会创建一个字典(在 javascript 中,它将是一个 JSON 与 observable 名称作为布尔属性),您将每个 observable 推送到“create”和一个在每个 observable 完成时应该执行的方法,该方法将遍历那个字典,如果都完成了做某事。 这将确保所有完成后的并行性和最终执行。

    var requests = {
        doRequest1: false,
        doRequest2: false,
        doRequest3: false
    };
    
    var checkIfCAllCompleted = name => {
        requests[name] = true;
        for (var property in requests) {
            if (object.hasOwnProperty(property)) {
                if (!property) {
                    return;
                }
            }
        }
        // all properties are true - do something here
        console.log("here");
    }
    this.server.doRequest1().then(() => checkIfCAllCompleted("doRequest1"));
    this.server.doRequest2().then(() => checkIfCAllCompleted("doRequest2"));
    this.server.doRequest3().then(() => checkIfCAllCompleted("doRequest3"));
    

    【讨论】:

      猜你喜欢
      • 2018-09-18
      • 1970-01-01
      • 2016-05-23
      • 2018-06-29
      • 1970-01-01
      • 1970-01-01
      • 2018-10-06
      • 2018-08-06
      • 1970-01-01
      相关资源
      最近更新 更多