我有两个Observable, getUser 和 getUserAvatar 。 它们都发出两个值-使用BehaviorSubject立即缓存,并在网络请求后返回true。
现在的代码以这种方式工作:
1)发送请求以获取用户并立即释放缓存的用户
2)发出缓存的用户后,代码进入concatMap内部,并首次执行getUserAvatar
3)getUserAvatar将请求发送到服务器,并立即发出缓存的userAvatar
4)一切都已完成,并且已缓存用户并返回了已化身的头像
5)一段时间后,真实用户返回并且getUser再次发出值
6)在这一步,我想防止第二次调用concatMap ,因为服务器请求已经在处理中,所以我只想返回“ USER LOADED”。
sendGetRequest('/user/').pipe(
concatMap(() => {
// HERE, after user data loaded, I have url for his avatar
return sendGetRequest('/avatar/').pipe();
}),
map(() => {
return 'USER LOADED';
})
)
服务器请求代码
sendGetRequest(url: string, ignoreCache?: boolean): any {
let responseSubj = new Subject();
const cachedData = this.cache.getItemForUrl(url);
const cacheAllowed = cachedData && !ignoreCache;
if (cacheAllowed) {
responseSubj = new BehaviorSubject(cachedData);
}
const getFromServer = this.http.get(environment.API_SERVER_URL + url, this.addAuth()).pipe(
filter((res: any) => {
if (cacheAllowed && JSON.stringify(cachedData) === JSON.stringify(res)) {
responseSubj.complete();
return false;
}
this.cache.setItemForUrl(url, res).then(() => {
responseSubj.complete();
});
return true;
}),
catchError((error, caught) => {
console.log('ERROR FROM GET REQUEST', error);
return throwError(error);
})
);
return merge(responseSubj, getFromServer);
}
答案 0 :(得分:1)
所以,我想这就是你所追求的:
https://stackblitz.com/edit/angular-2kaawf
因此,如您所见,我没有声明要获取缓存结果的任何主题。我并不是说您不应该使用“主题”。在这种情况下,您只是不需要它们。我添加了一个明确的“缓存和重新加载”按钮,目的只是为了说明您可以将主题用作什么。
如果重新加载页面,您将看到先前使用的数据已被重用。但是,当您清除缓存后,缓存的数据将消失,重新加载后将显示“ null”。
此代码将按预期工作。但是,如果您在可观察的user $上有2个订阅,则会得到一些意外的结果。要解决这些问题,请查看shareReplay运算符;)
答案 1 :(得分:-1)
您应该使用exhaustMap
而不是concatMap
。
exhaustMap
忽略其他值,直到该可观察值完成。
例如,
fromEvent(this.saveButton.nativeElement, 'click')
.pipe(
exhaustMap(() => this.saveCourse(this.form.value))
)
.subscribe();
如果现在我们单击保存,假设我们连续单击5次,则可以看到,在保存请求仍在进行时,我们按预期所做的点击!
示例来自angularuniveristy博客。