[英]Rxjs execute concatMap only once
我有兩個Observable, getUser和getUserAvatar 。 它們都發出兩個值 - 使用BehaviorSubject立即緩存,並在網絡請求后立即緩存。
現在代碼以這種方式工作:
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);
}
所以,我認為這就是你所追求的:
https://stackblitz.com/edit/angular-2kaawf
因此,正如您所看到的,我沒有聲明任何主題來獲取緩存的結果。 我不是說你不應該使用主題。 在這種情況下你只是不需要它們。 我添加了一個清除緩存和重新加載按鈕,以說明您可以使用的主題。
如果您重新加載頁面,您將看到以前使用的數據被重用。 但是,當您清除緩存時,緩存的數據將消失,重新加載后您將看到“null”。
此代碼將按預期工作。 但是,如果您在用戶$ observable上有2個訂閱,則會得到一些意外結果。 要解決這些問題,請查看shareReplay運算符;)
您應該使用exhaustMap
而不是concatMap
。
exhaustMap
忽略其他值,直到observable完成。
例如,
fromEvent(this.saveButton.nativeElement, 'click')
.pipe(
exhaustMap(() => this.saveCourse(this.form.value))
)
.subscribe();
如果我們現在點擊“保存”連續說5次,我們可以看到,我們在保存請求仍在進行時所做的點擊會被忽略,正如預期的那樣!
示例來自angularuniveristy博客。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.