简体   繁体   English

等待所有 Observable 完成

[英]Wait till all Observables are completed

I have few Observables like this one in my code.我的代码中很少有像这样的 Observable。

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

There could be any number of these Observables, so I need to write a function that checks if each Observable is done otherwise waits till each is finished.可能有任意数量的这些 Observable,所以我需要编写一个函数来检查每个 Observable 是否完成,否则等待每个 Observable 完成。

I'm assuming I can create an array push every new Observable there and when it's completed remove it by index.我假设我可以创建一个数组,将每个新的 Observable 推送到那里,并在完成后通过索引将其删除。 But is it good solution?但这是好的解决方案吗?

Where I want to use it.我想在哪里使用它。 For example I have a page where user upload photos any amount asynchronously and then he press Finish button.例如,我有一个页面,用户可以在其中异步上传任意数量的照片,然后按“完成”按钮。 Once he pressed Finish button I need to wait till ALL dynamically created Observables are completed.一旦他按下完成按钮,我需要等到所有动态创建的 Observable 完成。

you should use higher order observables for this, your exact use case will dictate the exact operator, but forkJoin seems a good candidate:您应该为此使用更高阶的 observables,您的确切用例将决定确切的运算符,但 forkJoin 似乎是一个不错的选择:

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

forkJoin won't emit till all innter observables have completed. forkJoin 在所有内部 observable 完成之前不会发出。 making it the operator of choice for waiting for multiple observables to complete.使其成为等待多个 observable 完成的首选操作符。 You can also feed it an array of observables.您还可以为它提供一组可观察值。 There are multiple other operators that may fulfill your case too, such as concat, merge, combineLatest or a few others.还有多个其他运算符也可以满足您的情况,例如 concat、merge、 combineLatest 或其他一些运算符。

edit based on more details:根据更多细节进行编辑:

in the use case described in your update, you'll still want to use a higher order observable, but forkjoin is not what you want.在您的更新中描述的用例中,您仍然希望使用更高阶的 observable,但 forkjoin 不是您想要的。 you'll want to use a local subject to accomplish the goal as wanting to kick off each observable as it is selected and waiting for them all to be done complicates things a little (but not too much):你会想要使用一个本地主题来完成目标,因为想要启动每个被选中的 observable 并等待它们全部完成会使事情变得有点复杂(但不是太多):

suppose you had a template like:假设您有一个模板,例如:

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

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

where the add photo button gets the users photo and all that, and finish is your completion, you could have a component like this:添加照片按钮获取用户照片和所有这些,完成就是你的完成,你可以有一个这样的组件:

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();
}

if you run this code, you'll see that the photo adds will emit in the subscribe handler as they complete, but complete will only fire once all the photo uploads have completed and the user has clicked finish.如果您运行此代码,您将看到照片添加完成后将在订阅处理程序中发出,但只有在所有照片上传完成且用户单击完成后才会触发完成。

here is a stackblitz demonstrating the functionality:这是一个演示功能的堆栈闪电战:

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

I'd create a dictionary (in javascript that would be a JSON with observable names as boolean properties) where you push each observable on "create" and a method which should execute on completion of each observable, which will iterate through that dictionary and if all completed do something.我将创建一个字典(在 javascript 中,它是一个 JSON,具有可观察名称作为布尔属性),您将在“创建”上推送每个 observable 和一个应该在每个 observable 完成时执行的方法,它将遍历该字典,如果都完成了做点什么。 That will ensure parallelism and final execution after all completed.这将确保所有完成后的并行性和最终执行。

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"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM