Angular中finalize在含switchMap的pipe内不生效问题排查与解决
问题分析与修复方案
一、switchMap 到底干啥用的
switchMap 是 RxJS 的核心操作符之一,核心逻辑就两点:
- 上游 Observable(这里就是弹窗确认的结果流)每发一个值,它会立刻取消之前还在运行的内部 Observable 请求
- 然后新建并订阅一个新的内部 Observable(这里就是调用
processService.doWork的API请求),把这个新请求的结果往下传
简单说就是“弃旧迎新”,适合这种用户确认后才触发单次API请求的场景,避免重复请求。
二、为啥你的代码会出问题
问题出在this.confirmation.warn返回的 Observable 上——它不是一个“一次性”的流。用户点击确认后,这个流并没有结束,还在维持着(比如弹窗可能还在监听其他操作)。而finalize操作符只有在整个上游流完成或者出错的时候才会执行。
所以当API请求成功返回时,上游的弹窗流还没结束,finalize就不会触发,isModalBusy就一直卡在true。而你加take(1)后,相当于强制这个流只取第一个确认值就结束,这样API请求完成后整个流就走完了,finalize自然就执行了。
三、修复方案
最直接的就是把take(1)加上,放在filter后面,确保用户确认一次后,弹窗的流就结束。修改后的代码如下:
run() { let inputParams = JSON.stringify(this.paramsInput); this.confirmation.warn( 'RunConfirmationMessage', 'AreYouSure', {messageLocalizationParams: []} ).pipe( filter(status => status === Confirmation.Status.confirm), take(1), // 加上这行,确保流只取一次值就完成 switchMap(() => { this.workOutput = { success: true, consoleOutput: "Executing now..." } this.activeTabId = 1; this.isModalBusy = true; return this.processService.doWork({work: this.work, workParams: inputParams}); }), finalize(() => { this.isModalBusy = false }), ).subscribe({ next: (result) => this.workOutput = result, error: (error: HttpErrorResponse) => this.workOutput = {success: false, errorMessage: error.message} as WorkOutput, }); }
另外也可以换个思路,把isModalBusy = false直接放在next回调里,同时保留error里的处理,但这样不如用finalize优雅,因为finalize不管成功还是失败都会执行,更适合处理这种清理状态的逻辑。
内容的提问来源于stack exchange,提问作者Balkan
相关产品推荐
相关产品推荐

