【问题标题】:RXJS - Multiple observable calls on array of propertiesRXJS - 对属性数组的多个可观察调用
【发布时间】:2019-08-13 21:11:09
【问题描述】:

我是 rxjs 的新手,我有一个相当简单的案例,我无法用 angular 解决。

我有一个 http 调用来检索一个组,这个组包含一个“伙伴 id”列表、一个“流派 id”列表和一个“区域 id”。

要通过“好友 ID”获取好友对象,我必须通过我的服务调用 API(返回 1 个具有给定 ID 的好友)。

要获取我的流派对象,我可以从我的商店中检索它们,区域也是如此。

问题是我无法用管道解决问题。

this.buddyService.getGroup(groupId).pipe(
    mergeMap((group) => forkJoin(
          mergeMap(() => forkJoin(group.buddyIds.map((id) => this.buddyService.getBuddy(id)))), 
          mergeMap(() => forkJoin(group.genreIds.map((id) => this.store.select(GenreState.genre(id))))),
          switchMap(() => this.store.select(RegionState.region(group.regionId))))
    ), takeUntil(this.destroyed$)
).subscribe(([group, buddies, genres, region]) => {

});

所以第一个 mergeMap 将在 1 个订阅中获取所有结果,然后我有 3 个子调用来获取好友、流派和区域。

我想要我的初始响应(组)和 1 订阅中的 3 个子调用的结果,显然这个解决方案不起作用,而且我似乎无法让其他东西起作用。

任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: angular typescript rxjs observable


    【解决方案1】:

    这个版本有点冗长,但可能更容易推理,因为它被分成了几个块。不过还没有测试过。

    import {combineLatest} from 'rxjs';
    
    ...
    
      const group$ = this.buddyService.getGroup(groupId);
      const buddies$ = group$.pipe(mergeMap(group => combineLatest(group.buddyIds.map((id) => this.buddyService.getBuddy(id))));
      const genres$ = group$.pipe(mergeMap(group => combineLatest(group.genreIds.map((id) => this.store.select(GenreState.genre(id))));
      const region$ = group$.pipe(switchMap(group => this.store.select(RegionState.region(group.regionId)))));
    
      combineLatest([group$, buddies$, genres$, region$])
        .pipe(takeUntil(this.destroyed$))
        .subscribe(([group, buddies, genres, region]) => {});
    

    【讨论】:

    • 我试过你的解决方案,它似乎没有打到订阅部分,有什么线索吗?
    • 所以 forkJoin 假设所有的 Observables 都完成了,但 store.select 可能不是这样。我已将最后一个 forkJoin 更改为 combineLatest,这可能会解决问题。
    • 或者,我们可以通过将 store.select 更改为“this.store.select(RegionState.region(group.regionId)).pipe(take(1))”来完成 store.select。
    • 我现在将示例中的所有 forkJoins 更改为 combineLatest,然后它应该可以工作。但是如果你想要的只是获得一个值,那么你应该改回 forkJoin,并在所有未完成的 observables 之后添加“.pipe(take(1))”。
    • 是的,问题确实出在 store.select 上(如果我在 store 上做一个 selectsnapshot 订阅它就可以了)。我会试试你的最新解决方案
    【解决方案2】:

    看来你的内心mergeMaps 太多了。试试这个

    this.buddyService.getGroup(groupId).pipe(
      mergeMap((group) => forkJoin(
        of(group),
        forkJoin(...group.buddyIds.map((id) => this.buddyService.getBuddy(id))), 
        forkJoin(...group.genreIds.map((id) => this.store.select(GenreState.genre(id)))),
        this.store.select(RegionState.region(group.regionId)))
      ),
      takeUntil(this.destroyed$)
    )
    .subscribe(([group, buddies, genres, region]) => {});
    

    主要问题是您将创建 Observables(如forkJoin)的“构造”方法与对现有 Observables(如@987654331)进行操作的运算符组合在一起@ 或 mergeMap)。

    自己测试差异:switchMap vs forkJoin

    我已经写了这个没有深度测试,所以它可能不会立即工作:)

    【讨论】:

    • 我会在晚上晚些时候尝试一下,如果它有效,请回复,不过谢谢,我对 rxjs 很陌生,所以很多:)
    • 你有没有 rxjs 官方文档之外的任何资源,我没有发现它们很清楚
    • @TanguyB,好吧,在实际方面——我强烈推荐我创建的rxjs playground。在理论上——我感觉到你的痛苦,当前的文档大多缺乏简单性和透明度。试试learnrxjs.io——他们有很好的例子,还有这个old book on RxJS 4,你可能会从中得到一些概念。 + 有几个关于 RxJS 的傻瓜课程,虽然它们是在付费墙后面。
    • @TanguyB,我刚刚搜索了一些 rxjs 资源——实际上,关于这个主题的教程和文章有很多。虽然因为我第一次看到它们中的大多数——我不能诚实地推荐它们。然而,这里有两个视频可以帮助您入门:RxJS Quick Start with Practical Examplesseries of video tuts by RxJS core contributors Ben Lesh and Tracy Lee。基本上只是谷歌周围,你会找到最适合你的! ;)
    • @嗨,我试过你的解决方案,订阅部分似乎没有,有什么线索吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 2016-01-21
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    相关资源
    最近更新 更多