如何在Angular 17中为HTTP请求实现加载Spinner?
Angular 17 HTTP请求加载Spinner实现方案
需求:开发Angular 17项目时,需要实现一个在HTTP请求期间显示的加载Spinner,要求单个或多个请求发起时显示Spinner,所有请求完成后隐藏,追求简洁高效的实现方式。
当前实现代码
app.component.html
@if (loading$ | async) { <ng-container> <div class="overlay"></div> <app-spinner></app-spinner> </ng-container> } <router-outlet></router-outlet>
app.component.ts
export class AppComponent { loading$ = this.loadingService.loading$; constructor(private loadingService: LoadingService) {} }
main.ts
bootstrapApplication(AppComponent, appConfig) .catch((err) => console.error(err));
app.config.ts
export const appConfig: ApplicationConfig = { providers: [ provideHttpClient(withInterceptors([networkInterceptorFn])), provideRouter(routes), provideAnimations(), provideAnimationsAsync() ] };
network.interceptor.ts
export const networkInterceptorFn: HttpInterceptorFn = (req, next) => { let totalRequests = 0; let requestsCompleted = 0; const loadingService = inject(LoadingService); loadingService.show(); totalRequests++; return next(req).pipe( finalize(() => { requestsCompleted++; if (requestsCompleted === totalRequests) { loadingService.hide(); totalRequests = 0; requestsCompleted = 0; } }) ); };
加载Spinner测试函数
constructor(private taskHttpService: TaskHttpService, private http: HttpClient) { this.fetchDataTmp(); } fetchDataTmp(): Observable<any>{ return this.http.get('https://jsonplaceholder.typicode.com/todos/1').pipe( delay(5000) ); }
核心优化:修复并发请求计数错误
当前实现的networkInterceptorFn存在逻辑缺陷——每个HTTP请求会创建独立的totalRequests和requestsCompleted变量,导致多请求并发时Spinner会提前隐藏。正确的做法是将请求计数逻辑统一移至LoadingService内部管理:
优化后的LoadingService
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class LoadingService { private loadingSubject = new BehaviorSubject<boolean>(false); private requestCount = 0; loading$ = this.loadingSubject.asObservable(); show(): void { this.requestCount++; this.loadingSubject.next(true); } hide(): void { this.requestCount--; if (this.requestCount <= 0) { this.requestCount = 0; this.loadingSubject.next(false); } } }
优化后的Interceptor
export const networkInterceptorFn: HttpInterceptorFn = (req, next) => { const loadingService = inject(LoadingService); loadingService.show(); return next(req).pipe( finalize(() => { loadingService.hide(); }) ); };
优化逻辑说明:
- 用全局的
requestCount追踪请求数量,每发起一个请求计数+1,完成一个计数-1 - 仅当计数归0时,才通知隐藏Spinner,确保多并发请求场景下Spinner持续显示到所有请求完成
内容的提问来源于stack exchange,提问作者coder
相关产品推荐
相关产品推荐

