如何在ngrx效果中在switchMap中引发错误

问题描述

我正在使用ngrx8,rxjs6和angular 9

登录后,我需要致电其他服务。当该服务引发错误时,我想catchError来处理它的部分问题,问题是我在try catch中捕获了错误,并且看到了日志,但是未触发catchError

简化代码

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

我的真实代码

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

            ofType(AuthActions.login),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);
                            }
                        }),);
    });

控制台输出

enter image description here

解决方法

而不是使用Async-Await语法来等待Promise返回的matrixService.initClient的完成(由于switchMap运算符未等待,因此在当前上下文中不起作用对于async函数),请考虑不等待它就将其返回,因为它将被转换成Observable(由于switchMap运算符接受Promise),从而导致{{1 }}正在等待。

this.userService.login
,

根据评论,我将对先前的答案进行一些修改

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

我切换顺序,总是先触发AuthActions.loginSuccess(),然后触发this.matrixService.initClient(userName,password)

catchError不需要被调用两次,服务调用生成的任何错误都将被最外层的catchError运算符捕获。