обработка ошибок эффектов ngrx

у меня есть очень простой вопрос относительно эффектов @ngrx: как игнорировать ошибку, которая происходит во время выполнения эффекта, чтобы она не влияла на выполнение будущего эффекта?

моя ситуация такова: у меня есть действие (логин) и эффект, слушающий это действие. Если внутри этого эффекта происходит ошибка, Я хочу ее игнорировать. Когда логин отправляется во второй раз после этой ошибки, эффект должен быть выполнен во второй раз.

моя первая попытка сделать это было:

  @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();
    });

диспетчер входа в систему в первый раз бросает и ловит ошибку, как и ожидалось. Однако, если я отправлю логин во второй раз после этого, ничего не произойдет; эффект не выполняется.

поэтому я попробовал следующий:

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

, но это приводит к бесконечному циклу... Знаете ли вы, как поймать ошибку, не предотвращая выполнение эффекта после этого?

3 ответов


на ngrx инфраструктура подписывается на эффект через поставщика, импортированного в приложение NgModule используя EffectsModule.run.

когда наблюдаемые ошибки и catch возвращает пустой obervable, составленный observable завершает и его подписчики отписаны-это часть Наблюдаемые Договору. И именно по этой причине вы не видите дальнейшего обращения LOGIN действия эффекта. Эффект отписывается по завершении и the ngrx инфраструктура не возобновите подписку.

как правило, у вас будет обработка ошибок внутри flatMap (ныне 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();
    })
  });

на catch составленный во внутреннее наблюдаемое увидит пустое наблюдаемое сплющенное / объединенное В влияние, поэтому никакое действие не будет испущено.


на @Effect поток завершение когда происходит ошибка, предотвращая любые дальнейшие действия.

решение перейти на одноразовые поток. Если в одноразовом потоке возникает ошибка, это нормально, так как main @Effect поток всегда остается живым, и будущие действия продолжают выполняться.

@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();
            });

    });

подробнее об этой технике в этот блог: Поиск фрикадельки: продолжить RxJS потоки, когда возникают ошибки


вот как я обрабатываю опцию уведомления или не уведомления о наблюдаемых, которые не нашли никаких данных:

 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())));
    }