2017-01-16 4 views
16

Ich habe eine sehr grundlegende Frage zu @ngrx-Effekten: Wie ignoriere ich einen Fehler, der während der Ausführung eines Effekts auftritt, so dass er die zukünftige Effektausführung nicht beeinflusst?ngrx effects error handling

Meine Situation ist wie folgt: Ich habe eine Aktion (LOGIN) und einen Effekt auf diese Aktion zu hören. Wenn innerhalb dieses Effekts ein Fehler auftritt, möchte ich ihn ignorieren. Wenn LOGIN ein zweites Mal nach diesem Fehler ausgelöst wird, sollte der Effekt ein zweites Mal ausgeführt werden.

Mein erster Versuch, dies zu tun war:

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

Dispatching LOGIN das erste Mal wirft und fängt den Fehler, wie erwartet. Wenn ich jedoch LOGIN ein zweites Mal nachschicke, passiert nichts; Der Effekt wird nicht ausgeführt.

Deshalb habe ich versucht, die folgenden:

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

, aber dies führt zu einer Endlosschleife ... Wissen Sie, wie der Fehler zu fangen, ohne danach Wirkung Ausführung zu verhindern?

+0

Ich weiß nicht, NGRX aber man kann wahrscheinlich nur '.retry()' auf dem Strom statt zu kontrollieren. – Gluck

Antwort

14

Die ngrx Infrastruktur schließt sich der Effekt über den Provider in die NgModule mit EffectsModule.run App importiert.

Wenn die beobachtbaren Fehler und catch eine leere obervable zurückgibt, vervollständigt das zusammengesetzte Observable und seine Abonnenten sind abgemeldet - das ist Teil der Observable Contract. Und das ist der Grund, warum Sie keine weitere Behandlung von LOGIN Aktionen in Ihrem Effekt sehen. Der Effekt wird nach Abschluss des Vorgangs abgemeldet, und die Infrastruktur ngrx wird nicht erneut abonniert.

Normalerweise würden Sie den Fehler haben in der flatMap Handling (jetzt genannt 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(); 
    }) 
    }); 

Die catch in den inneren beobachtbaren zusammengesetzt wird eine leere beobachtbaren abgeflacht/verschmolzen in den Effekt sehen, so dass keine Aktion wird ausgesendet werden.

1

das ist, wie ich die Option Griff auf Observable notifizierten werden soll oder nicht, die keine Daten gefunden:

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

Der @Effect Strom abgeschlossen wird, wenn der Fehler auftritt, weitere Aktionen zu verhindern .

Die Lösung besteht darin, zu einem Einwegstrom zu wechseln. Wenn innerhalb des Disposable-Streams ein Fehler auftritt, ist dies in Ordnung, da der Hauptdatenstrom immer am Leben bleibt und zukünftige Aktionen weiterhin ausgeführt werden.

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

    }); 

Mehr Informationen zu dieser Technik in diesem Blog-Eintrag: The Quest for Meatballs: Continue RxJS Streams When Errors Occur