ngrx影响错误处理

时间:2017-01-16 21:47:30

标签: rxjs ngrx

我有一个关于@ngrx效果的非常基本的问题:如何忽略在执行效果期间发生的错误,使其不会影响未来的效果执行?

我的情况如下:我有一个动作(LOGIN)和一个听取该动作的效果。如果在此效果中发生错误,我想忽略它。在此错误后第二次调度LOGIN时,应该再次执行该效果。

我的第一次尝试是:

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

第一次调度LOGIN并按预期捕获错误。但是,如果我之后第二次发送LOGIN,则没有任何反应;效果不会被执行。

因此我尝试了以下内容:

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

,但这导致无限循环...你知道如何在不阻止效果执行的情况下捕获错误吗?

3 个答案:

答案 0 :(得分:19)

ngrx基础设施通过使用NgModule导入应用EffectsModule.run的提供商订阅效果。

当可观察的错误和catch返回一个空的obervable时,组合的observable完成并且其订阅者被取消订阅 - 这是class path的一部分。这就是您认为没有进一步处理LOGIN动作的原因。该效果在完成时取消订阅,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();
    })
  });

组成内部observable的catch将看到一个空的observable展平/合并到效果中,因此不会发出任何动作。

答案 1 :(得分:4)

发生错误时,@Effect正在完成,从而阻止任何进一步的操作。

解决方案是切换到一次性流。如果在一次性流中发生错误,则可以,因为主@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();
            });

    });

此博客文章中有关此技术的更多信息:The Quest for Meatballs: Continue RxJS Streams When Errors Occur

答案 2 :(得分:1)

这就是我如何处理在没有找到任何数据的Observable上通知或不通知的选项:

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