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

在Angular中将每个请求存储到对象中是否属于常规开发实践?

Is This HTTP Request Caching Implementation Good Practice?

Hey Nick, let's break down your current caching code and talk through its strengths, areas for improvement, and whether it aligns with best practices.

First, the Strengths of Your Approach

Your code has some solid foundations that are in line with good caching practices:

  • Shared Subscriptions: Using publishReplay(1) + refCount() is a smart way to ensure multiple subscribers to the same request only trigger one HTTP call, with subsequent subscribers getting the cached response. This reduces unnecessary network traffic.
  • Context-Aware Cache Keys: You're combining request params with the default locale to create unique cache keys, which ensures different parameter sets or language contexts don't overwrite each other's cached data—this is a good call.

Areas to Improve (And Why They Matter)

While your core idea is sound, there are a few details that can make the implementation more robust and maintainable:

  1. Incorrect Store Type
    You initialized store = [] (an array), but you're using string keys to store Observables. Arrays are designed for numeric indices, so using string keys here is unconventional and can lead to unexpected behavior (like accidental key coercion to numbers). Instead, use an object with explicit typing:

    private store: { [key: string]: Observable<PostsInt[]> } = {};
    
  2. No Cache Invalidation
    Right now, once a request is cached, it stays in memory forever. If the backend data updates, your app will keep serving stale content until the page refreshes. For most applications, adding a cache expiration mechanism is critical. You could modify the store to cache both the Observable and a timestamp, then check if the cache is expired before using it:

    private store: { [key: string]: { observable: Observable<PostsInt[]>, timestamp: number } } = {};
    // When checking the cache:
    const CACHE_TTL = 300000; // 5 minutes in ms
    if (this.store[key] && Date.now() - this.store[key].timestamp < CACHE_TTL) {
      return this.store[key].observable;
    } else {
      // Re-fetch and update cache
    }
    
  3. Unhandled Error Caching
    If an HTTP request fails (e.g., network error, server error), the failed Observable will be cached. Every subsequent request for that key will immediately receive the same error, without attempting to re-fetch. Fix this by adding a catchError operator to remove the failed entry from the store:

    posts = posts.pipe(
      publishReplay(1),
      refCount(),
      catchError((error) => {
        delete this.store[key];
        return throwError(() => error);
      })
    );
    
  4. Fragile Cache Key Generation
    Using Object.values(params).join('') can lead to key collisions. For example, {a: '12', b: '3'} and {a: '1', b: '23'} will generate the same key ("123"). Instead, use JSON.stringify(params) to create a unique key that accounts for parameter names and order:

    const key = JSON.stringify(params) + APP_CONFIG.data.defaultLocale;
    
  5. Potential Memory Bloat
    Over time, your store can accumulate a lot of cached Observables, especially if your app has many unique parameter combinations. For long-running SPAs, this can lead to unnecessary memory usage. Consider adding a cleanup mechanism (e.g., periodically removing cached entries that haven't been accessed in a certain time) or using a more memory-efficient structure where possible.

Improved Code Example

Putting all these fixes together, here's a revised version of your function:

import { Observable, throwError } from 'rxjs';
import { publishReplay, refCount, catchError } from 'rxjs/operators';

private store: { [key: string]: { observable: Observable<PostsInt[]>, timestamp: number } } = {};
private readonly CACHE_TTL = 300000; // 5 minutes

fetchAll(params: any, cache = true): Observable<PostsInt[]> {
  if (!cache) {
    return this.http.get<PostsInt[]>(this.getApiUrl('/posts'), { params });
  }

  const key = JSON.stringify(params) + APP_CONFIG.data.defaultLocale;
  const now = Date.now();

  // Check if valid cache exists
  if (this.store[key] && now - this.store[key].timestamp < this.CACHE_TTL) {
    return this.store[key].observable;
  }

  // Create and cache the new observable
  const posts = this.http.get<PostsInt[]>(this.getApiUrl('/posts'), { params }).pipe(
    publishReplay(1),
    refCount(),
    catchError((error) => {
      delete this.store[key]; // Remove failed cache entry
      return throwError(() => error);
    })
  );

  this.store[key] = { observable: posts, timestamp: now };
  return posts;
}

Final Verdict

Your core approach to caching HTTP requests is absolutely a good practice—it reduces network calls and improves app performance. With the tweaks above, you'll make the implementation more robust, avoid edge cases, and align it with production-ready best practices.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:29:44