comment throwError dans switchMap dans l'effet ngrx
J'utilise ngrx8, rxjs6 et angular 9
Après la connexion, je dois appeler un autre service. lorsque ce service génère une erreur, je veux catchError une partie de mon effet pour le gérer, le problème est que j'attrape l'erreur dans try catch et que je vois le journal, mais qu'il catchError
n'est pas déclenché.
Code simplifié
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 }));
}),
);
});
Mon vrai 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 }));
}),
);
});
sortie console

Réponses
Plutôt que d'utiliser Async-Await
la syntaxe pour attendre que le Promise
retourné par matrixService.initClient
se termine (ce qui ne fonctionnerait pas dans le contexte actuel car l' switchMap
opérateur n'attend pas les async
fonctions), envisagez de le renvoyer sans l'attendre, car il serait converti en un Observable
(grâce à l' switchMap
opérateur accepter Promise
) ayant pour résultat d' this.userService.login
être attendu.
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 }));
})
)
);
sur la base des commentaires, je modifierai un peu les réponses précédentes
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 }));
})
)
);
J'inverse l'ordre, toujours en tirant AuthActions.loginSuccess()
, puis this.matrixService.initClient(userName, password)
.
catchError
n'a pas besoin d'être appelé deux fois, toute erreur générée par l'appel de service sera capturée dans l' catchError
opérateur le plus externe.