Captura errores en el Observable que se manejan devolviendo un Observable nuevo o lanzando un error
Signatura
Firma
catchError<T, O extends ObservableInput<any>>(selector: (err: any, caught: Observable<T>) => O): OperatorFunction<T, T | ObservedValueOf<O>>
Parámetros
Retorna
OperatorFunction<T, T | ObservedValueOf<O>>: Un Observable que se puede originar en el Observable fuente o en el Observable retornado por la función selector.
Descripción
catchError captura errores en el Observable fuente, manejándolos de dos maneras posibles: bien devolviendo un Observable nuevo o bien lanzando un nuevo error.
import { throwError, of } from"rxjs";import { catchError } from"rxjs/operators";consterror$=throwError("Oh no!");error$.pipe(catchError((error) => {throw`Lanzando un nuevo error: ${error}`; }) ).subscribe(console.log,console.error);// Salida: (Error) Lanzando un nuevo error: Oh no!
Capturar los errores de un Observable interno
Al capturar los errores que ocurren en un Observable interno (un Observable emitido por un Observable de orden superior), se debe tener cuidado a la hora de utilizar el operador catchError ya que, si se coloca en el sitio equivocado, el flujo del Observable fuente no seguirá ejecutándose tras capturar el error.
A continuación, se puede ver cómo el uso incorrecto de catchError hará que, después de capturar el error que devuelve la primera petición, el flujo se completará y no se harán las otras dos peticiones restantes:
import { map, concatMap, catchError } from"rxjs/operators";import { ajax } from"rxjs/ajax";import { of } from"rxjs";constpokemonId$=of(-3,5,6);functiongetPokemonName(id:number) {return ajax.getJSON(`https://pokeapi.co/api/v2/pokemon/${id}`).pipe(map(({ name }) => name));}pokemonId$.pipe(concatMap((id) =>getPokemonName(id)),catchError((error) =>of(`¡Oh no, ha ocurrido un error! ${error}`)) ).subscribe(console.log,console.error, () =>console.log("Completado"));// Salida: ¡Oh no, ha ocurrido un error! AjaxError: ajax error 404, Completado
Sin embargo, si se utiliza catchError en el Observable interno, el comportamiento es el que se busca: cuando falle la primera petición, se capturará el error y el flujo seguirá ejecutándose, realizando las dos peticiones restantes:
import { map, concatMap, catchError } from"rxjs/operators";import { ajax } from"rxjs/ajax";import { of } from"rxjs";constpokemonId$=of(-3,5,6);functiongetPokemonName(id:number) {return ajax.getJSON(`https://pokeapi.co/api/v2/pokemon/${id}`).pipe(map(({ name }) => name));}pokemonId$.pipe(concatMap((id) =>getPokemonName(id).pipe(catchError((error) =>of(`¡Oh no! ${error}`))) ) ).subscribe(console.log,console.error, () =>console.log("Completado"));// Salida: ¡Oh no, ha ocurrido un error!, charmeleon, charizard, Completado
Ejemplos de la documentación oficial
Continuar con un Observable diferente cuando ocurre un error
import { of } from"rxjs";import { map, catchError } from"rxjs/operators";of(1,2,3,4,5).pipe(map((n) => {if (n ===4) {throw"four!"; }return n; }),catchError((err) =>of("I","II","III","IV","V")) ).subscribe((x) =>console.log(x));// 1, 2, 3, I, II, III, IV, V
Reiniciar el Observable fuente en caso de error, parecido al operador retry()