Konrad Viltersten
Konrad Viltersten

Reputation: 39268

How to compound a series of consequential subscriptions in RxJS

I have approach according to the below.

this.service1.info
  .subscribe(a => this.service2.getDetails(a.id)
    .subscribe(b => {
      this.doStuff(b);
    })
  );

Recently, I noticed that we're going to have quite a few steps that gradually push more details to the client, so I'm anticipating the following atrocious pattern emerge.

this.service1.info
  .subscribe(a => this.service2.getDetails(a.id)
    ...
            .subscribe(z => { 
              this.doStuff (z);
            })
  );

Is there a nice trick in RxJS to handle such situations? I only need to perform an operation once all the steps in the consequential chain have been emitted/received. I've browsed through the docs but didn't find something that felt quite right. I suspect that it's there, just that my ignorance confuses me so I'm missing it.

Upvotes: 0

Views: 197

Answers (1)

wentjun
wentjun

Reputation: 42576

Yes, you are right. It is indeed an anti-pattern within RxJS to chain multiple subscribes.

A more elegant way of chaining these observable calls would be to make use of pipeable operators. In this scenario, the switchMap() operator would suffice.

As stated on the documentation, switchMap() will

Map to observable, complete previous inner observable, emit values.

this.service1.info
  .pipe(
    switchMap((a) => this.service2.getDetails(a.id)),
    switchMap((a) => this.service3.getDetails(a.id)),
    // switchMap((a) => this.service4.getDetails(a.id)),
    // subsequent chained methods
  ).subscribe(z => {
    // handle the rest when observables are returned
    this.doStuff(z);
  });

As you can see from the above pipe statement, we only call subscribe() once, and that will return the observable values. That is when we call the doStuff method.

Upvotes: 1

Related Questions