API调用完成后UI中Spinner未关闭的原因排查请求
问题排查与解决方案
核心原因
你的Spinner无法消失,主要是RxJS的Observable通知机制导致的:
- 当API调用触发
error回调时,complete回调不会被执行(error属于终止性通知,一旦触发就会跳过complete阶段),导致this.isSaving = false从未执行,Spinner一直处于显示状态。 - 即使API调用成功,若
visaSuccessHandler.execute内部存在未处理的异步逻辑,也可能间接影响状态更新,但最直接的问题还是error分支未重置状态。
解决方案
方案1:在所有分支中手动重置状态
在next和error回调中都添加this.isSaving = false,确保无论请求成功还是失败,都能关闭Spinner:
public onSave() { this.isSaving = true; this.formService.entityForm.markAsPristine(); this.visaSubmitHandler.execute({ application: this.formService.entityForm.value }).subscribe({ next: (response: IApplicationCreateResponse) => { this.stateRehydrationService.clearStateKey(this.formService.key); this.visaSuccessHandler.execute({ application: response.entity }); this.isSaving = false; // 成功后关闭Spinner }, error: (response: IApplicationCreateResponse) => { this.formService.entityForm.markAsDirty(); try { for (const error of response.errors) { const propertyName = `${error.propertyName[0].toLowerCase()}${error.propertyName.slice(1)}`; const control = this.formService.entityForm.get(propertyName) as AbstractControl; setErrors({ serverError: error.message }, control); } this.bottomSheet.open(DisplayErrorsComponent, { data: response.errors.map(e => e.message) }); } catch (e) { console.error(e); } this.isSaving = false; // 失败后关闭Spinner }, complete: () => { this.isSaving = false; // 保险:处理Observable正常完成的情况 } }); }
方案2:使用finalize操作符(更简洁)
RxJS的finalize操作符会在Observable无论完成还是出错时执行回调,适合统一处理状态重置:
import { finalize } from 'rxjs/operators'; public onSave() { this.isSaving = true; this.formService.entityForm.markAsPristine(); this.visaSubmitHandler.execute({ application: this.formService.entityForm.value }) .pipe(finalize(() => { this.isSaving = false; // 无论成功失败都会执行 })) .subscribe({ next: (response: IApplicationCreateResponse) => { this.stateRehydrationService.clearStateKey(this.formService.key); this.visaSuccessHandler.execute({ application: response.entity }); }, error: (response: IApplicationCreateResponse) => { this.formService.entityForm.markAsDirty(); try { for (const error of response.errors) { const propertyName = `${error.propertyName[0].toLowerCase()}${error.propertyName.slice(1)}`; const control = this.formService.entityForm.get(propertyName) as AbstractControl; setErrors({ serverError: error.message }, control); } this.bottomSheet.open(DisplayErrorsComponent, { data: response.errors.map(e => e.message) }); } catch (e) { console.error(e); } } }); }
额外注意点
- 确保
isSaving是组件的公共属性(或通过getter暴露),模板能正确读取到状态变化。 - 若
visaSuccessHandler.execute是异步操作且需要等待它完成后再关闭Spinner,需将其转换为Observable并使用switchMap等操作符串联,避免Spinner提前关闭。
内容的提问来源于stack exchange,提问作者Christos Segkani
相关产品推荐
相关产品推荐

