我仍然在使用RxJS,所以这可能是一个简单的问题。
目前我试图懒洋洋地对某些数据做出XHR请求,我只需要获取一次,然后在页面打开时无限期地缓存,我想我试图利用{{{} { 1}}使用Angular的HTTP客户端发出的值。到目前为止我基本上看起来像这样:
AsyncSubject
这几乎可以使用,因为在订阅@Injectable()
class AuthService {
user$ = new BehaviorSubject(null);
// do .switchMap() so we reset when the auth'ed user changes
extraInfo$ = this.user$.switchMap(() => {
return this.http.get('/api/account').share();
});
constructor(http: HttpClient) { }
...
}
之前不会发出请求,extraInfo$
应该阻止在我有超过1个观察者时发出其他请求。
但是,如果我取消订阅并且.share()
变冷(因为有0个订阅者),再次订阅它会导致再次发出请求。
现在我很想覆盖extraInfo$
上的._subscribe()
属性,这样我就可以在它获得第一个观察者时运行请求,但这感觉有些过于hackish。
答案 0 :(得分:1)
如果您想要执行请求,然后在任何后续订阅中缓存此结果,您可以更轻松地执行此操作:
@Injectable()
class AuthService {
user$ = new BehaviorSubject(null);
extraInfo$ = this.user$.switchMap(() => {
return this.http.get('/api/account').shareReplay(1);
});
constructor(http: HttpClient) { }
...
}
使用shareReplay(1)
解决了share
运营商遇到的问题。它们都是多播运营商,但具有不同的属性。你希望操作符是可重复的而不是可重试的(查看我在这个主题上写的这篇文章,以帮助你http://blog.kwintenp.com/multicasting-operators-in-rxjs/理解我的意思)。
请记住,如果您想无限期地缓存某个可观察的结果,shareReplay
就是您需要的结果。
答案 1 :(得分:0)
我最终想出了一些东西,以下是我需要的东西:
const lastFetchedInfo = new WeakMap();
@Injectable()
class AuthService {
user$ = new BehaviorSubject(null);
// do .switchMap() so we reset when the auth'ed user changes
extraInfo$ = this.user$.switchMap(user => !user ? Observable.empty() : new Observable((observer) => {
if (!lastFetchedInfo.has(user)) {
const subject = new BehaviorSubject(null);
lastFetchedInfo.set(user, subject.filter(o => o !== null));
this.http.get('/api/account').subscribe(info => subject.next(info));
}
const subscription = lastFetchedInfo.get(user);
return () => subscription.unsubscribe();
}));
constructor(http: HttpClient) { }
...
}
我决定使用BehaviorSubject
代替AsyncSubject
,因为如果需要,我可以扩展以设置刷新数据的时间间隔。