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

需求:基于Signal的多Observable异步操作状态跟踪工具(支持OnPush)

基于Signal的异步请求状态跟踪方案

实现思路

搭建一个全局状态管理服务,用Angular Signal跟踪所有动物相关请求的加载状态,同时包装原AnimalService的请求方法,自动处理状态更新。这样任何组件都能直接获取全局或单个请求的加载状态,完美适配OnPush变更检测策略。


1. 先定义状态类型

统一规范请求标识和状态结构:

type AnimalRequestKey = 'cats' | 'dogs' | 'chickens';

interface AnimalLoadingState {
  [key in AnimalRequestKey]: boolean;
}

2. 创建全局状态管理服务

这个服务是核心,负责维护状态信号、包装请求方法:

import { Injectable, inject, signal, computed } from '@angular/core';
import { AnimalService } from './animal.service';
import { finalize, Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class AnimalLoadingStateService {
  private readonly animalService = inject(AnimalService);
  // 存储单个请求的加载状态
  private readonly loadingStates = signal<AnimalLoadingState>({
    cats: false,
    dogs: false,
    chickens: false
  });

  // 计算信号:全局是否有动物请求在加载
  readonly isAnyAnimalLoading = computed(() => {
    const states = this.loadingStates();
    return Object.values(states).some(isLoading => isLoading);
  });

  // 获取单个请求的加载状态
  getLoadingState(key: AnimalRequestKey) {
    return computed(() => this.loadingStates()[key]);
  }

  // 通用包装方法:自动处理状态更新
  private wrapRequest<T>(key: AnimalRequestKey, request$: Observable<T>): Observable<T> {
    this.loadingStates.update(state => ({ ...state, [key]: true }));
    return request$.pipe(
      finalize(() => {
        this.loadingStates.update(state => ({ ...state, [key]: false }));
      })
    );
  }

  // 暴露包装后的请求方法
  fetchCats() {
    return this.wrapRequest('cats', this.animalService.fetchCats());
  }

  fetchDogs() {
    return this.wrapRequest('dogs', this.animalService.fetchDogs());
  }

  fetchChickens() {
    return this.wrapRequest('chickens', this.animalService.fetchChickens());
  }
}

3. 在OnPush组件中使用

组件A(触发请求)

import { Component, inject } from '@angular/core';
import { AnimalLoadingStateService } from './animal-loading-state.service';
import { ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-component-a',
  template: `
    <button (click)="loadCats()">加载猫数据</button>
    <button (click)="loadDogs()">加载狗数据</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ComponentA {
  private readonly loadingStateService = inject(AnimalLoadingStateService);

  loadCats() {
    this.loadingStateService.fetchCats().subscribe(data => {
      // 处理猫数据逻辑
    });
  }

  loadDogs() {
    this.loadingStateService.fetchDogs().subscribe(data => {
      // 处理狗数据逻辑
    });
  }
}

组件B(显示全局加载状态)

import { Component, inject } from '@angular/core';
import { AnimalLoadingStateService } from './animal-loading-state.service';
import { ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-component-b',
  template: `
    <div *ngIf="isLoading()" class="loading-spinner">加载中...</div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ComponentB {
  private readonly loadingStateService = inject(AnimalLoadingStateService);

  // 直接绑定计算信号,OnPush会自动响应变更
  isLoading = this.loadingStateService.isAnyAnimalLoading;
}

可选扩展

  • 可以给状态结构添加error字段,跟踪请求错误状态
  • 若要支持更多请求,只需扩展AnimalRequestKey和对应的请求方法即可

内容的提问来源于stack exchange,提问作者Francesco Borzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:42:42