如何在Angular中处理按顺序执行的间隔请求?
问题修复思路
两个问题的根源都来自RxJS操作符选择和终止条件的配置错误:
switchMap的特性是上游抛出新值时自动取消未完成的内部流订阅,你用interval(1000)每秒触发一次新值,自然会把前一秒还在请求的startAudit直接取消,不符合需要等待返回结果做判断的需求- 原有
takeWhile只控制了轮询次数,没有对接startAudit的返回结果做判断,所以无法提前终止轮询
修复后的代码
fetchData(data) { // 声明30秒超时流,作为轮询的最长终止条件 const timeout$ = timer(30000); this.myService.createCase(data).pipe( finalize(() => this.loadingCreate = false), catchError(e => { this.loadingScan = false; this.loadingResult = false; return of(null); }), // 过滤createCase返回空的场景,直接终止流避免无效执行 filter(res => !!res?.caseSystemId), map(res => res.caseSystemId), switchMap(caseId => this.myService.startScreen(caseId).pipe( catchError(() => { this.loadingScan = false; return of(null); }), finalize(() => this.loadingScan = false), // 过滤startScreen返回空的场景 filter(res => !!res), // 改用expand做递归轮询,保证前一次请求完成后再发起下一次,不会被意外取消 expand(() => timer(1000).pipe( concatMap(() => this.myService.startAudit(caseId)), catchError(e => of(null)) )), // 双终止条件:触发30秒超时 或 startAudit返回非空结果 takeUntil(timeout$), takeWhile(auditRes => !auditRes, true), // 拿到有效audit结果后再调用结果查询接口 switchMap(() => this.myService.getResults(caseId).pipe( catchError(e => of(null)), finalize(() => this.loadingResult = false) )) )) ).subscribe(res => { if (res) { this.response = this.filterByPrior(res); } }) }
关键改动说明
- 替换轮询实现:放弃
interval+switchMap的组合,改用expand操作符实现递归轮询,保证前一次startAudit请求完成后再等待1秒发起下一次,不会出现请求被意外取消的问题 - 新增双终止逻辑:用
takeUntil(timer(30000))控制最长轮询时间不超过30秒,用takeWhile判断startAudit的返回值,只要返回非空就立刻终止轮询 - 增加空值过滤:在
createCase和startScreen返回后新增filter操作符,返回为空时直接终止流,避免后续无效的空参数请求 - 调整请求顺序:保证只有
startAudit返回非空结果后才调用getResults,不会出现无效的结果查询请求
内容的提问来源于stack exchange,提问作者Sunstrike527
相关产品推荐
相关产品推荐

