The simplest way for RxJS error handling is to provide an error callback when subscribing an Observable.
Error callback in subscribe
Ex:
  of(1, 2, 3, 4)
    .pipe(
      map(
        next => {
          // Throw an error if the input value equals to 2
          if (next === 2) {
            throw new Error('My Error');
          }
          return next;
        }
      )
    )
    .subscribe(
      value => console.log('Success: ' + value),
      err => console.log('Handle the error: ' + err),
      () => console.log('complete'),
    );
Result:
  Success: 1
  Handle the error: Error: My ErrorAccording to the example above, we can handle errors simply in subscribe error callback, but this approach is very simple, and we cannot do much thing such as replacing the emitted value from errors or retrying it. Using catchError and retryWhen Operator, we can handle errors in Observable Stream, which make us have more controls.
Catch and Replace Approach
Using catchError, we can return a new Observable which emits a default value if there is an error out. Then, the error callback in subscribe will not be called.. 
Ex: 
  of(1, 2, 3, 4)
    .pipe(
      map(
        next => {
          // Throw an error if the input value equals to 2
          if (next === 2) {
            throw new Error('My Error');
          }
          return next;
        }
      ),
      // Return default value if it catches errors
      catchError(err => of(0)),
    )
    .subscribe(
      value => console.log('Success: ' + value),
      err => console.log('Handle the error: ' + err),
      () => console.log('complete'),
  );
Result:
  Success: 1
  Success: 0
  completeAccording to the result above, we can notice that the success and complete callback were triggered instead of error callback.
Catch and Rethrow Approach
We also can use catchError operator to catch the error and deal with it locally. And rethrow it to make this error be caught by error callback in subscribe. 
Ex: 
  of(1, 2, 3, 4)
    .pipe(
      map(
        next => {
          // Throw an error if input value equals to 2
          if (next === 2) {
            throw new Error('My Error');
          }
          return next;
        }
      ),
      // Catch and deal with the error locally
      // And rethrow this error
      catchError(
        err => {
          console.log('Handle error in Observable Stream');
          return throwError(err);
        }
      ),
    )
    .subscribe(
      value => console.log('Success: ' + value),
      err => console.log('Handle the error: ' + err),
      () => console.log('complete'),
  );
Result:
  Success: 1
  Handle error in Observable Stream
  Handle the error: Error: My Error
Retry
We can utilize retryWhen operator to re-subscribe the error-out Stream. 
Ex: 
  of(1, 2, 3, 4)
    .pipe(
      map(
        next => {
          // Throw an error if input value equals to 2 (with half chance)
          if (next === 2 && Math.random() > 0.5) {
            throw new Error('My Error');
          }
          return next;
        }
      ),
      // Retry after 2 seconds if there is an error
      retryWhen(
        error => {
          return error
            .pipe(
              delayWhen(() => timer(2000))
            );
        }
      )
    )
    .subscribe(
      value => console.log('Success: ' + value + ' in ' + 
        Date.now() / 1000),
      err => console.log('Handle the error: ' + err),
      () => console.log('complete'),
  );
Result:
  Success: 1 in 1636809816.598
  Success: 1 in 1636809818.613
  Success: 2 in 1636809818.614
  Success: 3 in 1636809818.614
  Success: 4 in 1636809818.614
  complete
Catch and Continue
According to this stackoverflow article, we even can re-subscribe the source Observable. 
Ex: 
  of(1, 2, 3, 4)
    .pipe(
      // Using higher-order operator
      switchMap(
        next => of(next)
          .pipe(
            map(
              v => {
                // Throw an error if input value equals to 2
                if (v === 2) {
                  throw new Error('My Error');
                }
                return next;
              }
            ),
            // Catch error and return the default value
            catchError(error => of(0))
        )
      ),
    )
    .subscribe(
      value => console.log('Success: ' + value),
      err => console.log('Handle the error: ' + err),
      () => console.log('complete'),
  );
Result:
  Success: 1
  Success: 0
  Success: 3
  Success: 4
  complete
No comments:
Post a Comment