【问题标题】:Rxjs execute concatMap only onceRxjs 只执行一次 concatMap
【发布时间】:2019-05-25 12:28:06
【问题描述】:

我有两个 Observable,getUsergetUserAvatar。 它们都发出两个值 - 使用 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);
}

【问题讨论】:

  • 请添加执行您描述的逻辑的代码
  • 我添加了执行服务器请求的函数代码
  • 你的第六点是什么。这不是很清楚。您正在调用 getUser() 但不是 getUserAvatar() 因为?还有,真实用户是什么意思?
  • 您可以使用forkJoin 来代替请求和as of RxJS 6.5+ we can use a dictionary of sources,这在这里可能很方便learnrxjs.io/operators/combination/forkjoin.html
  • 你让这种方式太复杂了......你实际上甚至不需要科目......我会帮助你,但你的样本太混乱了。第一个代码部分与 getUser 和 getUserAvatar 调用之间是否有任何关系,第二部分与 sendGetRequest 调用之间是否存在任何关系?另外,您使用 concatMap 而不是 mergeMap 或 switchMap 是否有特定原因?

标签: angular rxjs rxjs6


【解决方案1】:

所以,我认为这就是你所追求的:

https://stackblitz.com/edit/angular-2kaawf

所以,如您所见,我没有声明任何主题来获取缓存的结果。我并不是说你不应该使用主题。在这种情况下,您只是不需要它们。我包含了一个清除缓存和重新加载按钮,只是为了说明您可以使用主题。

如果您重新加载页面,您会看到之前使用的数据被重复使用。但是,当您清除缓存时,缓存的数据消失了,重新加载后您将看到“null”。

此代码将按预期工作。然而,如果你在 user$ observable 上有 2 个订阅,你会得到一些意想不到的结果。要解决这些问题,请查看 shareReplay 运算符;)

【讨论】:

    【解决方案2】:

    您应该使用exhaustMap 而不是concatMap

    exhaustMap 在 observable 完成之前忽略其他值。

    例如,

    fromEvent(this.saveButton.nativeElement, 'click')
    .pipe(
        exhaustMap(() => this.saveCourse(this.form.value))
    )
    .subscribe();
    

    如果我们现在连续点击 5 次保存,我们可以看到,我们在保存请求仍在进行时所做的点击,正如预期的那样被忽略了!

    示例来自angularuniveristy 博客。

    Detailed explanation of exhaustMap

    【讨论】:

      猜你喜欢
      • 2017-10-05
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多