How to throwError in switchMap im ngrx-Effekt
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
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 }));
})
)
);
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.