Search code examples
rxjsrxjs-pipeable-operators

How to make 2 async calls with rxjs one after the other regardless if the first succeeds or fails


I have a use case where I need to make two async calls. order is important here. The first call needs to complete (or fail) before starting the next call.

I have a example code below showing what I need but it is not done in a reactive way (ie. using rxjs operators)

public performDBTasks(): Observable<void> {
    return Observable.create(
    (observer)=> {
        this.performDBTask1().subscribe(
        ()=> {
            this.performDBTask2().subscribe(
            ()=> {
                observer.next();
                observer.complete();
            },
            ()=> {
                observer.error();
            });
        },
        (error)=> {
            this.performDBTask2().subscribe(
            ()=> {
                observer.next();
                observer.complete();
            },
            ()=> {
                observer.error();
            });         
        }); 
    });
}

Update: just to clarify the two calls are http like calls so they will return data & complete or error. There will be no stream of data.


Solution

  • Use a switchMap and a catchError to both return performDBTask2

    const { of, throwError, switchMap, tap, catchError } = rxjs;
    
    const performDBTask1 = () =>
      Math.random() > .5 // 50/50 chance of erroring
        ? of('Success Task 1')
        : throwError('Error Task 1');
    
    const performDBTask2 = () => of('Success Task 2');
    
    performDBTask1().pipe(
      tap({
        next: (val) => { console.log(val); },
        error: (error) => { console.log(error); }
      }),
      catchError(() => performDBTask2()),
      switchMap(() => performDBTask2())
    ).subscribe((val) => {
      console.log(val);
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.8.0/rxjs.umd.min.js"></script>

    Everytime you hit the Run code snippet button above there is a 50/50 chance of performDBTask1 failing but performDBTask2 always succeeds.