from example compat rxjs ngrx

rxjs - example - manejo de errores de efectos



rxjs-compat (3)

Tengo una pregunta muy básica relacionada con los efectos de @ngrx: ¿Cómo ignorar un error que ocurre durante la ejecución de un efecto de manera que no afecte la ejecución futura del efecto?

Mi situación es la siguiente: tengo una acción (INICIAR SESIÓN) y un efecto al escuchar esa acción. Si ocurre un error dentro de este efecto, quiero ignorarlo. Cuando LOGIN se envía una segunda vez después de este error, el efecto se debe ejecutar una segunda vez.

Mi primer intento de hacer esto fue:

@Effect() login$ = this.actions$ .ofType(''LOGIN'') .flatMap(async () => { console.debug(''LOGIN''); // throw an error let x = [];x[0](); }) .catch(err => { console.error(''Error at login'', err); return Observable.empty(); });

Despachando LOGIN la primera vez lanza y atrapa el error, como se esperaba. Sin embargo, si despacho LOGIN una segunda vez después, no pasa nada; El efecto no se ejecuta.

Por eso probé lo siguiente:

.catch(err => { return this.login$; });

, pero esto da lugar a un bucle sin fin ... ¿Sabe cómo detectar el error sin impedir la ejecución del efecto después?


La infraestructura ngrx suscribe al efecto a través del proveedor importado en el NgModule la aplicación utilizando EffectsModule.run .

Cuando los errores y las catch observables devuelven un obervable vacío, el observable compuesto se completa y sus suscriptores se cancelan, eso es parte del Contrato observable . Y esa es la razón por la que no ve más manejo de las acciones de LOGIN en su efecto. El efecto se cancela cuando finaliza y la infraestructura ngrx no vuelve a suscribirse.

Normalmente, tendría el manejo de errores dentro de flatMap (ahora llamado mergeMap ):

import { Actions, Effect, toPayload } from "@ngrx/effects"; @Effect() login$ = this.actions$ .ofType(''LOGIN'') .map(toPayload) .flatMap(payload => Observable .from(Promise.reject(''Boom!'')) .catch(error => { console.error(''Error at login'', error); return Observable.empty(); }) });

La catch compuesta en el observable interior verá un observable vacío aplanado / fusionado en el efecto, por lo que no se emitirá ninguna acción.


La secuencia de @Effect está completando cuando se produce el error, impidiendo cualquier acción adicional.

La solución es cambiar a un flujo desechable. Si ocurre un error dentro del flujo desechable, está bien, ya que el flujo principal de @Effect siempre permanece activo y las acciones futuras continúan ejecutándose.

@Effect() login$ = this.actions$ .ofType(''LOGIN'') .switchMap(action => { // This is the disposable stream! // Errors can safely occur in here without killing the original stream return Rx.Observable.of(action) .map(action => { // Code here that throws an error }) .catch(error => { // You could also return an ''Error'' action here instead return Observable.empty(); }); });

Más información sobre esta técnica en esta publicación del blog: La búsqueda de albóndigas: continuar las transmisiones de RxJS cuando se producen errores


así es como manejo la opción de ser notificado o no de los Observables que no encontraron ningún dato:

public listenCampaignValueChanged(emitOnEmpty: boolean = false): Observable<CampaignsModelExt> { var campaignIdSelected$ = this.ngrxStore.select(store => store.appDb.uiState.campaign.campaignSelected) var campaigns$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaigns); return campaignIdSelected$ .combineLatest(campaigns$, (campaignId: number, campaigns: List<CampaignsModelExt>) => { return campaigns.find((i_campaign: CampaignsModelExt) => { return i_campaign.getCampaignId() == campaignId; }); }).flatMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty()))); }