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

使用shareReplay缓存Observable后,如何刷新并获取新值用于其他Observable

问题:shareReplay缓存请求后,如何等待刷新后的新值?

我通过shareReplay(1)缓存HTTP请求以避免重复调用,同时用BehaviorSubject触发API刷新,核心实现代码如下:

private _refreshResponse$ = new BehaviorSubject<void>(undefined);

public response$: Observable<any> = this._refreshResponse$.pipe(
  switchMap(() => this.http.get<any>(this.apiUrl)),
  map((o) => o.message),
  shareReplay(1)
);

constructor(private http: HttpClient) {
  this.response$.subscribe();
}

public onRefreshClick() {
  this.refreshResponse();
}

public refreshResponse() {
  this._refreshResponse$.next();
}

点击onRefreshClick()可以正常触发API刷新,但新增的onDoSomeWork()方法中,先执行一个HTTP调用,再触发刷新,紧接着从response$获取到的仍是旧值:

public onDoSomeWork() {
  this.fakeHttpCall()
    .pipe(
      tap(() => this.refreshResponse()),
      switchMap(() =>
        this.response$.pipe(
          take(1),
          tap((o) => console.log(o))
        )
      )
    )
    .subscribe();
}

问题根源是refreshResponse()仅触发新请求,不会等待请求完成,而response$的shareReplay(1)会立刻返回缓存的旧值。我不想在response$的全局订阅中处理逻辑,也不想用延迟这种临时方案,该如何确保获取到刷新后的新值?


解决方案1:在取值时跳过旧缓存

修改onDoSomeWork()的管道逻辑,触发刷新后跳过response$的旧缓存值,等待并获取新值:

public onDoSomeWork() {
  this.fakeHttpCall()
    .pipe(
      switchMap(() => 
        // 先触发刷新,再跳过旧缓存取新值
        this._refreshResponse$.pipe(
          first(), // 触发一次刷新信号
          switchMap(() => this.response$.pipe(skip(1), take(1))) // 跳过旧缓存,取刷新后的第一个新值
        )
      ),
      tap((o) => console.log(o))
    )
    .subscribe();
}

逻辑说明:

  • this._refreshResponse$.pipe(first()) 等价于调用refreshResponse(),触发新的HTTP请求
  • response$.pipe(skip(1), take(1)) 跳过shareReplay缓存的旧值,等待本次刷新请求返回的新值并仅取一次

解决方案2:重构refreshResponse方法返回新值Observable

让refreshResponse()直接返回一个Observable,该Observable会在刷新完成后发出新值:

public refreshResponse(): Observable<any> {
  return new Observable(observer => {
    this._refreshResponse$.next();
    // 订阅response$,跳过旧值,取新值后通知观察者
    const sub = this.response$.pipe(skip(1), take(1)).subscribe(observer);
    return () => sub.unsubscribe();
  });
}

// 调用时直接订阅refreshResponse的返回值
public onDoSomeWork() {
  this.fakeHttpCall()
    .pipe(
      switchMap(() => this.refreshResponse()),
      tap((o) => console.log(o))
    )
    .subscribe();
}

逻辑说明:

  • refreshResponse()内部触发刷新信号后,订阅response$并跳过旧缓存,将新值传递给调用方
  • 调用方无需再处理response$的缓存逻辑,直接通过switchMap获取刷新后的新值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 07:08:20