Rxjs仅执行一次concatMap

时间:2019-05-25 12:28:06

标签: angular rxjs rxjs6

我有两个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);
}

2 个答案:

答案 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博客。

Detailed explanation of exhaustMap