简体   繁体   中英

Subscribe inside subscribe: How to wait for both to finish in single subscription

I'm new to RXJS and I have one thing that I want to achieve but I don't know how.

I Have 2 API calls. But the second one depends on the value of the first one. The problem is that I want to handle both calls with one subscribe so the finalize triggers when both subscriptions are finished. Here is how I do it now where the finalize triggers after first observable finishes and don't waits for second one.

private getTemplate(){
this.loading = true;
this.service.getTemplate()
.pipe(
  finalize(() => this.loading = false)
)
.subscribe(
  (response) => {
    if (response) {
       this.createImage(response.link);
    }
  }
)

}

public createImage(link: string) {
this.service.createImage(link)
.subscribe(
  (response) => {
    this.image = response;
  }
)

I would handle it with a switchMap

private getTemplate(){
  this.loading = true
  this.a2vService.getNetworkTemplate().pipe(
    filter(response => !!response),
    switchMap(response => this.createImage(response.link)),
    finalize(() => this.loading = false)
  ).subscribe()
}

public createImage(link: string) {
  return this.service.createImage(link).pipe(
    tap(response => {
      this.image = response
    })
  )
)

The switchMap will execute the second observable after the first one emitted. Since both Observables are in a single pipe() , you can put the finalize() here too which will trigger when the second observable emitted.

Also important to return the Observable from createImage so it can be used inside the pipe() .

As you can see, the .subscribe() is empty above. We can actually put the finalize stuff here and it should behave the same.

private getTemplate(){
  this.loading = true
  this.a2vService.getNetworkTemplate().pipe(
    filter(response => !!response),
    switchMap(response => this.createImage(response.link))
  ).subscribe(() => {
    this.loading = false
  })
}

How to pass the data from getNetworkTemplate to the subscribe() callback:

private getTemplate(){
  this.loading = true
  this.a2vService.getNetworkTemplate().pipe(
    filter(response => !!response),
    switchMap(response => 
      combineLatest([of(response), this.createImage(response.link)])
    )
  ).subscribe(([networkTemplateResponse, createImageResponse]) => {
    this.loading = false
  })
}

You can use switchMap to subscribe to your second stream based on the result of the first. You can use filter to ensure you only move on to the second if the first response passes ( if (response) ).

You can write this something like this:

private getTemplate() {

  this.loading = true;
  this.a2vService.getNetworkTemplate().pipe(

    filter(response => !!response),
    switchMap(resp => this.service.createImage(resp.link)),
    finalize(() => this.loading = false)

  ).subscribe(resp => this.image = resp);
  
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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