如何处理无内部Observable的NGRX effect错误且不终止effect?
问题根源
你当前写法的核心问题是catchError放在了effect的外层主管道上:当map中执行canThrow抛出同步错误时,错误会直接传到外层的catchError,catchError返回的of(FailedAction())完成后,整个外层Observable流就会结束,对应的effect自然会停止响应后续的action。
正确实现方式
核心原则是把可能抛错的逻辑隔离在子流中处理,绝对不要让错误冒到外层的action主管道上,有两种常用写法:
写法1:用defer包裹同步函数+内部流捕获错误
根据你需要的并发策略选择对应的高阶Map操作符(switchMap/mergeMap/concatMap/exhaustMap),把逻辑放到内部流中处理,错误捕获也放在内部流层级:
public myEffect$ = createEffect(() => this.actions$.pipe( ofType(DoSomethingAction), switchMap(() => // defer会把同步函数的执行纳入Observable管控,同步抛出的错误会正常进入流的错误通道 defer(() => canThrow()).pipe( map(() => SucceededAction()), // catchError仅作用于当前子流,错误触发后只会结束本次子流,不会影响外层主循环 catchError(() => of(FailedAction())) ) ) ), );
写法2:纯同步逻辑直接用try/catch
如果canThrow是纯同步逻辑,不需要处理异步Observable/Promise,也可以直接在高阶Map操作符内部用原生try/catch捕获错误,写法更直白:
public myEffect$ = createEffect(() => this.actions$.pipe( ofType(DoSomethingAction), switchMap(() => { try { canThrow(); return of(SucceededAction()); } catch (e) { return of(FailedAction()); } }) ), );
注意事项
- 禁止把
catchError放在和ofType平级的外层管道,除非你明确希望错误触发后终止整个effect - 所有可能抛错的逻辑(不管是同步函数、Promise还是Observable调用),都要放到高阶Map操作符创建的内部流中处理错误,保证外层action流始终处于存活状态,能持续响应后续的action触发
- 如果后续
canThrow改成返回Promise的异步函数,只需要把defer(() => canThrow())换成from(canThrow())即可,其余错误处理逻辑完全不用改
内容的提问来源于stack exchange,提问作者wlf
相关产品推荐
相关产品推荐

