Angular拦截器结合ion-loading异常:idle提前执行问题求助
问题分析与解决方案
问题的核心是Ionic的Loading.present()是异步操作(返回Promise),你的BusyService.busy()方法没有等待这个异步操作完成就继续执行后续逻辑,导致idle()在loading还没完成显示时就被调用,出现日志顺序混乱的情况。
解决步骤
改造
BusyService,让异步操作顺序可控
给busy()和idle()添加异步处理,同时加入请求计数器处理并发请求(避免多请求重复显示/关闭loading):import { Injectable } from '@angular/core'; import { LoadingController, Loading } from '@ionic/angular'; @Injectable({ providedIn: 'root' }) export class BusyService { private loading: Loading | null = null; private activeRequests = 0; constructor(private loadingController: LoadingController) {} async busy(): Promise<void> { this.activeRequests++; // 只有第一个请求进来时才创建并显示loading if (this.activeRequests === 1) { this.loading = await this.loadingController.create({ message: '加载中...' }); await this.loading.present(); console.log('present'); } console.log('busy'); } async idle(): Promise<void> { this.activeRequests--; console.log('idle'); // 所有请求都完成后才关闭loading if (this.activeRequests === 0 && this.loading) { await this.loading.dismiss(); this.loading = null; } } }调整拦截器,确保异步顺序
因为HttpInterceptor.intercept()必须返回Observable,不能直接用async/await,所以用fromPromise将busy()的异步操作转为Observable,保证先完成loading显示再发起请求:import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable, fromPromise } from 'rxjs'; import { finalize, switchMap } from 'rxjs/operators'; import { BusyService } from './busy.service'; @Injectable() export class LoadingInterceptor implements HttpInterceptor { constructor(private busyService: BusyService) {} intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { // 先执行busy()完成loading显示,再发起请求 return fromPromise(this.busyService.busy()).pipe( switchMap(() => next.handle(request)), // 请求完成(成功/失败)后执行idle()关闭loading finalize(async () => await this.busyService.idle()) ); } }
为什么这样有效
busy()通过await等待loading的创建和显示完成,确保busy()执行结束时,loading已经在页面上显示。- 拦截器里用
fromPromise和switchMap保证了先完成loading显示,再发起HTTP请求的顺序。 finalize里的await this.busyService.idle()确保关闭loading的操作不会提前执行,同时请求计数器避免了多请求场景下的loading闪烁问题。
内容的提问来源于stack exchange,提问作者Enrico Frison
相关产品推荐
相关产品推荐

