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

Angular:如何在服务组件中缓存API调用响应供其他组件调用?

How to Cache API Responses in an Angular Service (and Share Across Components)

Great question! Let's break this down clearly—since you want to cache API responses in an Angular service and make that cache accessible to other components, the singleton service pattern is the perfect fit here. Angular services are singleton by default when provided in the root injector, which means every component that injects the service shares the same instance. This makes them ideal for storing shared state like cached API data.

Step-by-Step Implementation

1. Create a Singleton API Service

First, create a service that handles your API calls and cache logic. Using providedIn: 'root' ensures it's a singleton, so all components share the same cache.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root' // Critical: Ensures one service instance across the app
})
export class ApiCacheService {
  // Use a Map to store cached data (key = API URL, value = response)
  private readonly cache = new Map<string, any>();

  constructor(private http: HttpClient) { }

  /**
   * Fetch data with cache support
   * @param apiUrl The API endpoint to call
   * @returns Observable of the data (cached or fresh)
   */
  fetchWithCache(apiUrl: string): Observable<any> {
    // Check if data exists in cache
    if (this.cache.has(apiUrl)) {
      console.log(`Returning cached data for ${apiUrl}`);
      // Wrap cached data in an Observable to keep the API consistent
      return of(this.cache.get(apiUrl));
    }

    // If no cache, make the API call and store the response
    return this.http.get(apiUrl).pipe(
      tap(response => {
        console.log(`Caching data for ${apiUrl}`);
        this.cache.set(apiUrl, response);
      })
    );
  }

  /**
   * Clear cache for a specific URL or the entire cache
   * @param apiUrl Optional URL to clear; omit to clear all
   */
  clearCache(apiUrl?: string): void {
    if (apiUrl) {
      this.cache.delete(apiUrl);
    } else {
      this.cache.clear();
    }
  }
}

2. Use the Cached Service in Components

Any component that needs the data can inject this service and call fetchWithCache()—the first call will fetch fresh data and cache it, while subsequent calls will immediately return the cached version.

import { Component, OnInit } from '@angular/core';
import { ApiCacheService } from './api-cache.service';

@Component({
  selector: 'app-user-list',
  template: `
    <div *ngIf="users">
      <h2>Users (Cached)</h2>
      <ul>
        <li *ngFor="let user of users">{{ user.name }}</li>
      </ul>
    </div>
  `
})
export class UserListComponent implements OnInit {
  users: any[] = [];

  constructor(private apiCacheService: ApiCacheService) { }

  ngOnInit(): void {
    this.apiCacheService.fetchWithCache('https://jsonplaceholder.typicode.com/users')
      .subscribe(users => {
        this.users = users;
      });
  }
}

Optional Enhancements

Add Cache Expiration

If you want cached data to expire after a certain time (e.g., 1 hour), modify the cache to store timestamped entries:

interface CachedEntry {
  data: any;
  timestamp: number;
}

private readonly cache = new Map<string, CachedEntry>();
private readonly cacheTTL = 3600000; // 1 hour in milliseconds

fetchWithCache(apiUrl: string): Observable<any> {
  const cachedEntry = this.cache.get(apiUrl);
  
  if (cachedEntry) {
    const now = Date.now();
    // Check if cache is still valid
    if (now - cachedEntry.timestamp < this.cacheTTL) {
      return of(cachedEntry.data);
    } else {
      this.cache.delete(apiUrl); // Remove expired entry
    }
  }

  return this.http.get(apiUrl).pipe(
    tap(response => {
      this.cache.set(apiUrl, {
        data: response,
        timestamp: Date.now()
      });
    })
  );
}

Persist Cache Across Page Refreshes

To keep cache data even after the user refreshes the page, replace the Map with localStorage:

private getCache(): Map<string, any> {
  const cachedStr = localStorage.getItem('apiCache');
  return cachedStr ? new Map(JSON.parse(cachedStr)) : new Map();
}

private saveCache(cache: Map<string, any>): void {
  localStorage.setItem('apiCache', JSON.stringify(Array.from(cache.entries())));
}

fetchWithCache(apiUrl: string): Observable<any> {
  const cache = this.getCache();
  
  if (cache.has(apiUrl)) {
    return of(cache.get(apiUrl));
  }

  return this.http.get(apiUrl).pipe(
    tap(response => {
      cache.set(apiUrl, response);
      this.saveCache(cache);
    })
  );
}

Why Singleton Services Are the Best Fit

Angular's root-provided services are singletons by design—there's only one instance running in your app. This means:

  • All components inject the same service instance, so they all access the exact same cache.
  • You don't need to manually sync cache data between components or use complex state management (unless your app requires it for other reasons).
  • The cache logic is centralized in one place, making it easy to maintain or update later.

内容的提问来源于stack exchange,提问作者vaibhav naik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:12:25