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