我还在适应RxJS的过程中,所以这可能是一个简单的问题。
目前,我正在尝试懒惰地对某些数据发出XHR请求,这些数据只需要获取一次,然后在页面打开时无限期地缓存。我认为,通过尝试利用从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()应该防止发出额外的请求。
但是,如果我取消订阅它,并且extraInfo$变冷(因为有0个订阅者),再次订阅它会导致再次发出额外的请求。
现在,我很想覆盖AsyncSubject上的._subscribe()属性,这样我就可以在请求获得第一个观察者时运行它,但这感觉有点太黑客了。
发布于 2017-10-06 05:24:56
如果您想要执行一个请求,然后在任何后续订阅中缓存此请求的结果,则可以更轻松地完成此操作:
@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就是你需要的。
发布于 2017-10-06 05:15:34
我最终想出了一些东西,下面是我所需要的:
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,因为如果需要,我可以扩展以设置刷新数据的间隔。
https://stackoverflow.com/questions/46576998
复制相似问题