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

如何用RxJS在后台更新Angular应用的缓存数据

解决方案:用RxJS流实现"先缓存后后台更新"逻辑

你需要重构数据获取逻辑,让Observable先发射缓存数据(如果存在),同时在后台发起API请求对比哈希,不匹配时更新缓存并触发通知。以下是具体实现步骤:

1. 重构数据获取方法,合并缓存与API流

修改countries服务中的方法,创建一个能同时处理缓存和API请求的Observable:

import { Observable, merge, of, Subject } from 'rxjs';
import { filter, tap, distinctUntilChanged } from 'rxjs/operators';

// 在服务中添加Subject用于通知数据更新
private dataUpdated$ = new Subject<boolean>();
public dataUpdated$ = this.dataUpdated$.asObservable();

public getCountriesWithCacheUpdate$(): Observable<IRawCountryData[]> {
  // 构建缓存数据流:仅当存在缓存时发射数据
  const cachedData$ = of(this.cache.getCache<IRawCountryData[]>(this.localStorageKeys.countries)).pipe(
    filter(data => data !== null)
  );

  // 构建API数据流:请求最新数据并处理缓存更新
  const apiData$ = this.api.get$<IRawCountryData[]>(this.host).pipe(
    tap(apiData => {
      const cachedData = this.cache.getCache<IRawCountryData[]>(this.localStorageKeys.countries);
      
      if (!cachedData) {
        // 首次请求:直接缓存数据与哈希
        this.cacheCountries(apiData);
      } else {
        // 对比哈希判断是否需要更新
        if (!this.isCacheUpToDate(apiData)) {
          this.cacheCountries(apiData);
          // 触发数据更新通知
          this.dataUpdated$.next(true);
        }
      }
    })
  );

  // 合并两个流:先发射缓存(如果有),再发射API数据
  return merge(cachedData$, apiData$).pipe(
    // 避免重复发射相同数据
    distinctUntilChanged((prev, curr) => this.isCacheUpToDate(curr))
  );
}

2. 完善缓存与哈希对比逻辑

更新缓存方法和哈希校验逻辑,确保同时存储数据和对应的哈希值:

private cacheCountries(countries: IRawCountryData[]): void {
  const hash = this.calculateHash(countries);
  this.cache.setCache(this.localStorageKeys.countries, countries);
  this.cache.setCache(this.localStorageKeys.countriesHash, hash);
}

private isCacheUpToDate(newCountries: IRawCountryData[]): boolean {
  const cachedHash = this.cache.getCache<string>(this.localStorageKeys.countriesHash);
  if (!cachedHash) return false;
  const newHash = this.calculateHash(newCountries);
  return cachedHash === newHash;
}

// 简单哈希计算实现(实际项目可使用crypto-js等专业库)
private calculateHash(data: any): string {
  const str = JSON.stringify(data);
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    hash = ((hash << 5) - hash) + str.charCodeAt(i);
    hash |= 0; // 转为32位整数
  }
  return hash.toString();
}

3. 修改初始化逻辑,先展示缓存再监听更新

更新initGame方法,先展示缓存数据,同时订阅数据更新通知:

private initGame(): void {
  this.layout.showLoader();

  this.countries
    .getCountriesWithCacheUpdate$()
    .pipe(
      takeUntilDestroyed(this.destroyRef),
      take(1), // 先取缓存数据展示
      finalize(() => {
        this.layout.hideLoader();
      }),
      map(rawCountries => this.countriesFilter.transform(rawCountries)),
    )
    .subscribe(countries => {
      this.playService.setCountries(countries);
      this.playService.nextQuestion();
    });

  // 订阅数据更新通知,显示过期提示
  this.countries.dataUpdated$.pipe(
    takeUntilDestroyed(this.destroyRef)
  ).subscribe(() => {
    // 替换为你的通知逻辑(如Toast、弹窗)
    this.notificationService.show('数据已更新,请刷新页面或重新开始游戏');
  });
}

核心逻辑说明

  • 缓存优先展示:通过merge操作符先发射缓存数据,确保用户快速看到内容,不会因API请求延迟等待。
  • 后台异步更新:API请求在后台执行,完全不阻塞UI,对比哈希后仅在数据变化时更新缓存并通知用户。
  • 内存泄漏防护:全程使用takeUntilDestroyed确保组件销毁时自动取消订阅,避免内存泄漏问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 18:05:58