通常,在有角度的应用程序中,我有一些服务,需要通过http请求检索一些数据,并通过BehaviorSubject将其共享给消费者。它具有这样的实现:
class Service {
private data = new BehaviorSubject();
getData() {
if (!this.data.getValue()) {
anyHttpCall().subscribe(res => this.data.next(res));
}
return this.data.asObservable();
}
}
这种方法的主要原理是,当应用程序的某些组件在没有值时同时调用getData()时,它将触发多个http调用并发出数据,因此我发现了两种防止它的方法:
1)存储表明请求状态的布尔变量
class Service {
private data = new BehaviorSubject();
private pendingResult = false;
getData() {
if (!this.data.value && !this.pendingResult) {
this.pendingResult = true;
anyHttpCall().subscribe(res => {
this.data.next(res);
this.pendingResult = false;
}
}
return this.data.asObservable();
}
}
2)在服务构造函数中获取数据
class Service {
private data = new BehaviorSubject();
constructor() {
anyHttpCall().subscribe(resthis.data.next(res));
}
getData() {
return this.data.asObservable();
}
}
那么,哪种方法是最好的,为什么?
答案 0 :(得分:1)
最好的方法是使用rxjs shareReplay 。该运算符返回一个Observable,它共享对基础源的单个订阅。换句话说,使我们的可观察性变得炙手可热。
const CACHE_SIZE = 1;
class Service {
private _data$: Observable<YourType>;
get data(): Observable<YourType> {
if (!this._data$) {
this._data$ = anyHttpCall()
.pipe(shareReplay({ refCount: true, bufferSize: CACHE_SIZE })
);
}
return this._data$;
}
}
bufferSize 确定重播缓冲区的最大元素数,即为每个订阅者缓存和重播的元素数。
这篇文章对此做得很好:https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.html
答案 1 :(得分:0)
如何初始化在构造器中通过初始调用getData
而变得很热的流?然后将第一个结果缓存在ReplaySubject
class Service {
private init = new Subject();
private data = new ReplaySubject(1);
constructor() {
this.init.pipe(
take(1),
switchMap(() => anyHttpCall())
)
.subscribe(res => this.data.next(res));
}
getData() {
this.init.next();
return this.data.asObservable();
}
}
答案 2 :(得分:0)
您的选择如何?
1)应该可以,但对我来说,它需要手工编写很多代码。
2)想象用户不会调用getData
方法,但是您已经发送了冗余请求。
有一个非常方便的运算符shareReplay
,它将帮助您使冷观测变得很热。
import { Observable } from 'rxjs';
import { shareReplay } from 'rxjs/operators';
export class Service {
private cache$: Observable<any>;
...
getData() {
if (!this.cache$) {
this.cache$ = this.anyHttpCall().pipe(
shareReplay(1)
);
}
return this.cache$;
}
}