Home > Mobile >  How can I execute 2 http calls after each other, but do not wait for the second one to complete, usi
How can I execute 2 http calls after each other, but do not wait for the second one to complete, usi

Time:05-10

I have the following requirement:

  • execute HTTP call A
  • wait for A to finish
  • execute HTTP call B
  • do not wait for B to finish
  • return result of HTTP call A

This seemed like a good case for the Rxjs tap operator, since call B is considered a 'side effect'. This is the code (subscribing to the result of this function is done elsewhere in the code):

public call(): Observable<any> {
  return this.http.get('/operation/a').pipe(
    tap(() => {
      this.http.get('/operation/b');
    })
  );
}

I noticed call B is not getting executed, because no one is subscribing to it. The following code fixes the problem:

public call(): Observable<any> {
  return this.http.get('/operation/a').pipe(
    tap(() => {
      this.http.get('/operation/b').pipe(take(1)).subscribe();
    })
  );
}

However, this feels icky, since we now have 2 subscriptions: one inside the tap, the other one when calling this method. Technically it is not a problem, since the observable within the tap will complete and therefore it doesn't need to be unsubscribed, but if feels off.

I do not know how else to implement a 'fire and forget' without waiting for the results of call B. Is there a 'proper' way to do so with Rxjs?

CodePudding user response:

I don't see anything wrong with the implementation actually. Also since Angular HTTP calls only emit single value, the take(1) is redundant. If you're worried about hanging subscriptions, you could explicitly close them (eg. in the ngOnDestroy() hook). See here for more info.

However if you wish to have only a single subscription, you could use the combineLatest with a startWith piped to the 2nd observable. Without startWith(null) the subscriber wouldn't receive the emission from '/operation/a' until '/operation/b' has emitted.

Then you could use map operator to ignore the 2nd observable's emission.

Note: I'm sure there could be better solutions to this problem. The following is the quickest I could come up with

import { combineLatest, startWith } from 'rxjs';
import { map } from 'rxjs';

public call(): Observable<any> {
  return combineLatest({
    a: this.http.get('/operation/a'),
    b: this.http.get('/operation/b').pipe(startWith(null))
  }).pipe(
    map(({a, b}) => a)
  );
}

CodePudding user response:

Just subscribe to it instead of piping?

public call(): void {
  this.http.get('/operation/a').subscribe((a) => {
      this.http.get('/operation/b').subscribe((b) => { ... });
  });
}

Also it's better to use firstValueFrom instead of .pipe(take(1)), but it's not even necessary in this case.

  • Related