4

What is "best practices" for chaining a sequence of HttpClient calls (assume the current call depends on the results of the previous calls)? The following solution is functional but apparently not recommended. Each get returns an Observable. Use of the "pipe" operator preferred in solution (the newer approach in RxJs).

ngOnInit() {
  this.firstService.get().subscribe((first) => {
    this.secondService.get().subscribe(second => {
      this.thirdService.get().subscribe(third => {
        ... possibly more nested calls ...
      })
    })
  })
}
Dan Def
  • 1,836
  • 2
  • 21
  • 39
Rick O'Shea
  • 1,410
  • 19
  • 15
  • Possible duplicate of [How to do the chain sequence in rxjs](https://stackoverflow.com/questions/37748241/how-to-do-the-chain-sequence-in-rxjs) – Pac0 Jan 20 '19 at 22:39

2 Answers2

13

Your code is far beyond best practice. Never do subscription inside another.

If your tasks are three seperate tasks/observables which do not depends each other, then consider to use forkJoin (all Observables start at the same time and when the last observable finishes It returns result)

let observable1(param1);
let observable2(param2);
let observable3(param3);

let joinedObservables = forkJoin(observable1, observable2, observable3).subscribe(x => {
  let result1 = x[0];
  let result2 = x[1];
  let result3 = x[2];

  ...
});

If their results depends on each other you can use switchMap, flatMap, mergeMap, exhaustMap (check differences)

let resultObservable =  return this.observable1().pipe(mergeMap((param1) => {
  return this.observable2().pipe(map((param1) => {

    ....        

    return <result>;
  }));
}));

resultObservable.subscribe(x => {
   ...
});
Derviş Kayımbaşıoğlu
  • 28,492
  • 4
  • 50
  • 72
2

If the reason why you need nested calls is to use data from the previous calls, I recommend using the pipe operator with mergeMaps and more pipes/maps to return the next calls in place of the previous.

Should be something similar to (subscribes and unsubscribes omitted):

this.firstService.pipe(
    mergeMap(res =>
        this.secondService.get().pipe(
            map(data => data),
        ),
    ... <more as needed>
);

If they don't need to be nested, it's easier to do this.service.get().toPromise() inside a promiseAll.

  • I don't see any advantage in using Promises which are a legacy version of Observable (that emit once) and even when making a HTTP call (completes after receive) there are benefits to using an Observable and associated operators. – Rick O'Shea Jan 21 '19 at 16:52
  • What makes a promise the legacy version of an observable? async/await styles of programming with promises are both very new and widely used. Angular uses both frequently for different purposes. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function shows their utility expanding even more so recently. It's just another opinion and another style of tools to use to do a similar job. The point here is one-shot (promise) vs stream (observable). –  Jan 21 '19 at 16:59