使用shareReplay缓存Observable后,如何刷新并获取新值用于其他Observable
我通过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
相关产品推荐
相关产品推荐

