Anutrix
Anutrix

Reputation: 273

How to subscribe to dynamically generated observable?

Obs1$.subscribe((data1) => {
    const generatedStuff = doSomethingFunction(data1);
    
    generatedStuff.Obs2$.subscribe(() => {
        doSomethingElse();
    });
});

This is my current solution. As you can see above, I have a function doSomethingFunction that generates an object generatedStuff with data from first observable.

This object contains an observable that needs to modified after it is created. Since it doesn't exist till first observable finishes there's no way to subscribe to it earlier.

Note that doSomethingFunction and generatedStuff are external and aren't supposed to be modified.

So subscribe inside subscribe is the only solution I could come up but I know it's bad practice so wanted to know if there's an alternative.

Upvotes: 1

Views: 583

Answers (1)

Mrk Sef
Mrk Sef

Reputation: 8022

The most direct translation:

Obs1$.pipe(
  mergeMap((data1) => {
    const generatedStuff = doSomethingFunction(data1);
    return generatedStuff.Obs2$;
  })
).subscribe(() => {
  doSomethingElse();
})

Remove the clutter:

obs1$.pipe(
  mergeMap(data1 => doSomethingFunction(data1).obs2$)
).subscribe(() => doSomethingElse());

Another way to write the same thing:

obs1$.pipe(
  map(data1 => doSomethingFunction(data1)),
  mergeMap(generatedStuff => generatedStuff.obs2$)
).subscribe(() => doSomethingElse());

if doSomethingFunction and doSomethingElse don't use the this keyword, are lambdas (use => sytax), or are otherwise already bound:

obs1$.pipe(
  map(doSomethingFunction),
  mergeMap(generatedStuff => generatedStuff.obs2$)
).subscribe(doSomethingElse);

Higher order operators:

mergeMap is one of many higher-order operators. The fundamental thing that a higher order operator is meant to do is to subscribe to dynamically generated observables.

RxJS will subscribe to any observable returned from mergeMap.

It's not the only operator that does this, concatMap, switchMap, and exhaustMap are included among the most popular such operators. What do they do and how do they differ?

Observables emit 0-n values over an undefined amount of time. Taking your example, what happens if obs1$ emits three values back to back? mergeMap will be generating three dynamic observables back to back as well.


How do those three observables interact with one another?

mergeMap manages this the same way that nested subscribe calls would manage it. It subscribes to all the dynamically created observables as soon as it generates them and then just keeps passing forward emissions from any source observable in whatever order they happen to appear.

concatMap only subscribes to one observable at a time. It waits for the previous observable to finish before subscribing to the next one. So each new dynamically created observable waits in a queue.

switchMap only subscribes to one observable at a time. If it gets a new dynamic observable while the previous one is still running, it just cancels the previous one.

exhaustMap only subscribes to one observable at a time. It refuses to generate any new dynamic observables while it's still running one. It does this by simply throwing away anything new.


So you can see that mergeMap and concatMap are cousins. They don't lose any information. They run run observables in parallel or in sequence respectively.

Similarly, switchMap and exhaustMap are cousins. They DO lose information, either favoring the newest or the oldest observable they received respectively.

Upvotes: 3

Related Questions