ngrx效果中switchMap如何抛出错误

how to throwError in switchMap in the ngrx effect

我正在使用 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),
            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 }));
            }),
        );
    });

控制台输出

而不是使用 Async-Await 语法等待 matrixService.initClient 返回的 Promise 完成(由于 switchMap 运算符,这在当前上下文中不起作用不等待 async 函数),考虑在不等待它的情况下返回它,因为它会被转换为 Observable(感谢 switchMap 运算符接受 Promise)导致 this.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 }));
    })
  )
);

根据评论我会稍微修改一下之前的答案

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运算符中被捕获。