You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 17:33:15