Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding nesting subscriptions in Angular 2+?

Tags:

angular

rxjs

I have 2 endpoints:

  • 1 endpoint to get current user logged.
  • 1 endpoint to get grants of this user.

Actually I use:

this.user
  .subscribe((e) => {
     this.grants.get(e)
        .subscribe((x) => {
            console.log(x)
         })
  })

But this is an anti-pattern of Angular 2+/RxJS.

I would like to know how to do this following Angular/RxJS best practices.

Thanks

like image 236
Carlos A. S. Moretti Avatar asked Sep 01 '20 10:09

Carlos A. S. Moretti


1 Answers

Avoiding nested subscriptions depends on the nature of the observables and how they depend on each other:

Co-dependent observables

When an observable (this.grants.get()) depends on the notification from another observable (this.user), you could use any of the RxJS higher order mapping operators switchMap, mergeMap, concatMap and exhaustMap. Each has their own purpose. You could find the differences between them here.

Brief differences b/n them

  • switchMap - cancel inner observable if the outer observable emits
  • mergeMap - trigger inner observable for each outer notification (flatten the outer notifications)
  • concatMap - essentially mergeMap with single concurrent request at any time (flattens the outer notifications but emit them in order)
  • exhaustMap - ignore outer notifications if inner observable hasn't completed

Illustration using switchMap operator

this.user.pipe(
  switchMap(e => this.grants.get(e))
).subscribe((x) => {
  console.log(x)
});

Independent observables

If the observables are independent of each other, you could use RxJS functions like forkJoin, combineLatest or zip to trigger the observables in parallel.

Brief differences b/n them

  • forkJoinα - emit only when all the observables complete
  • combineLatestα,β - emit when any of the observables emit (observables w/o emissions will emit old value)
  • zipα,β - emit when all of the observables emit

Illustration using forkJoin

forkJoin(this.obs1, this.obs2, ...).subscribe(
  res => console.log(res)
);

α - emits an array of notifications from each observable (eg. (this.obs1, this.obs2, ...) will emit ['res from obs1', 'res from obs2', ...]).

β - all observables should emit atleast once for the operator to emit

like image 97
ruth Avatar answered Oct 18 '22 03:10

ruth