Angular中catchError内switchMap仅首次执行的问题排查
问题原因
switchMap用法错误
你写的switchMap回调没有返回Observable,这不符合它的设计要求——switchMap必须接收一个能返回Observable的函数,用来把当前值转换成新的数据流。虽然RxJS会自动把无返回值的情况转成Observable.of(undefined),但这种写法会导致流的行为不符合预期,甚至触发隐式的流完成操作。父流被终止导致后续操作失效
第一次错误处理时,catchError返回的Observable在执行完switchMap(发出undefined后就完成了),这会让被catchError包裹的原父数据流进入完成状态。虽然后续错误还是会触发catchError(所以第一个日志每次都打印),但父流已经处于完成状态,此时getSomeServerValue()虽然被调用,返回的Observable也被订阅,但后续的tap和switchMap不会执行——因为完成状态的流不会处理新的订阅逻辑。额外可能:getSomeServerValue的缓存特性
如果getSomeServerValue内部用了shareReplay这类缓存操作符,第一次调用后会缓存结果,后续调用直接返回缓存值。但就算是这样,tap也应该每次订阅都执行,除非缓存的Observable已经完成且没有新值发出。不过结合你说的“调用总是被触发”,这个可能性不大。
解决办法
修正switchMap的写法:确保
switchMap的回调返回有效的Observable,哪怕只是返回当前值的流:catchError(error => { console.log("this line is logged each time") return this.someServiceApi.getSomeServerValue().pipe( tap(t => console.log("this line should log every time now")), switchMap(someServerValue => { console.log("this line should log every time now") // 返回一个Observable,示例返回当前值,可根据业务需求调整 return of(someServerValue); }) ) })保证父流持续运行:如果原父流是需要一直监听的(比如NgRx的Actions流),要确保
catchError返回的Observable不会让父流终止。可以返回一个永远不完成的流(比如never()),或者根据业务逻辑返回能让父流继续处理后续事件的流。
内容的提问来源于stack exchange,提问作者escplat12

