How to throwError in switchMap im ngrx-Effekt

Aug 19 2020

Ich verwende ngrx8, rxjs6 und Angular 9

Nach der Anmeldung muss ich einen anderen Dienst anrufen. Wenn dieser Dienst einen Fehler auslöst, möchte ich einen catchError-Teil meines Effekts, um ihn zu behandeln. Das Problem ist, dass ich den Fehler in try catch abfange und das Protokoll sehe, aber catchErrornicht ausgelöst wird.

Vereinfachter Code

    login$ = createEffect(() => {
        return this.actions$.pipe(

            ofType(AuthActions.login),
            switchMap((action) =>
                this.userService.login(action.userName, action.password)
                    .pipe(
                        switchMap((token) => {
                            return throwError(new Error('hello'));
                        }),
                        map((token) => AuthActions.loginSuccess()),
                        catchError((error) => {
                            console.error('error', error); // I don't see this in console

                            return of(AppError({ error }));
                        })),
            ),
            catchError((error) => {
                console.error('error 2', error);

                return of(AppError({ error }));
            }),
        );
    });

Mein echter Code

    login$ = createEffect(() => {
        return this.actions$.pipe(

            ofType(AuthActions.login),
            switchMap((action) =>
                this.userService.login(action.userName, action.password)
                    .pipe(
                        switchMap(async (token) => {
                            try {
                                await this.matrixService.initClient(action.userName, action.password);

                                return of(token);
                            }
                            catch (error) {
                                console.log('catch error', error); // I see this in console

                                return throwError(error);
                            }
                        }),
                        map((token) => AuthActions.loginSuccess()),
                        catchError((error) => {
                            console.error('error', error); // I don't see this in console

                            return of(AppError({ error }));
                        })),
            ),
            catchError((error) => {
                console.error('error 2', error);

                return of(AppError({ error }));
            }),
        );
    });

Konsolenausgabe

Antworten

1 RafiHenig Aug 19 2020 at 04:23

Anstatt die Syntax zu verwenden, um auf den Abschluss des zurückgegebenen by Async-Awaitzu warten (was im aktuellen Kontext nicht funktionieren würde, da der Operator nicht auf Funktionen wartet), ziehen Sie in Betracht, es zurückzugeben, ohne darauf zu warten, da es in ein (Dank an operator akzeptieren ) was dazu führt, dass erwartet wird.PromisematrixService.initClientswitchMapasyncObservableswitchMapPromisethis.userService.login

login$ = createEffect(() => this.actions$
  .pipe(
    ofType(AuthActions.login),
    switchMap(({ userName, password }) => this.userService.login(userName, password)
      .pipe(
        switchMap(() => this.matrixService.initClient(userName, password)),
        map((token) => AuthActions.loginSuccess()),
        catchError((error) => {
          console.error('error', error);
          return of(AppError({ error }));
        })
      )
    ),
    catchError((error) => {
      console.error('error 2', error);
      return of(AppError({ error }));
    })
  )
);
HamzaZaidi Aug 19 2020 at 22:01

Basierend auf den Kommentaren werde ich die vorherigen Antworten ein wenig ändern

login$ = createEffect(() => this.actions$
  .pipe(
    ofType(AuthActions.login),
    switchMap(({ userName, password }) => this.userService.login(userName, password)
      .pipe(
        map((token) => AuthActions.loginSuccess())
        tap(() => this.matrixService.initClient(userName, password)),
      )
    ),
    catchError((error) => {
      console.error('error 2', error);
      return of(AppError({ error }));
    })
  )
);

Ich wechsle die Reihenfolge, schieße immer AuthActions.loginSuccess()und dann this.matrixService.initClient(userName, password).

catchErrormuss nicht zweimal aufgerufen werden, jeder Fehler, der durch den Dienstaufruf generiert wird, wird im äußersten catchErrorOperator abgefangen.