【问题标题】:How to get rid of multiple nested switchMap with early returns如何摆脱具有早期返回的多个嵌套 switchMap
【发布时间】:2021-07-26 22:03:01
【问题描述】:

我有 3 个端点返回即将发生的、当前的、过去的事件。我应该只显示未来最远的那个。为了优化调用而不是一次调用所有端点。我编写了一个简单的 RxJs 流,我在其中调用第一个端点,如果它不返回数据,我调用第二个,依此类推。代码如下所示:

this.eventsService.getUpcoming(id).pipe(
      switchMap((upcoming) => {
        if (upcoming.length) {
          return of(upcoming);
        }
        return this.eventsService.getCurrent(id).pipe(
          switchMap((current) => {
            if (current.length) {
              return of(current);
            }
            return this.eventsService.getPast(id)
          })
        );
      }),
    // some other pipe operators map etc.

开关映射中可以没有嵌套的开关映射吗?

【问题讨论】:

    标签: javascript angular typescript rxjs


    【解决方案1】:

    我认为您可以只使用concat() 使调用顺序,然后take(1)skipWhile() 在第一个有用的响应到达时自动完成:

    concat(
      this.eventsService.getUpcoming(id),
      this.eventsService.getCurrent(id),
      this.eventsService.getPast(id)
    ).pipe(
      skipWhile(response => response.length === 0),
      defaultIfEmpty([]),
      take(1),
    );
    

    take(1) 将在skipWhile 中的第一项不符合条件时完成链。

    【讨论】:

    • 我看到这个解决方案的一个问题是,如果没有任何调用返回任何数据,那么 observable 将在没有任何发射的情况下完成。
    • 确实如此。您可以使用defaultIfEmpty() 确保它始终至少发出一次。
    • 标记为答案,因为它是最干净的解决方案。
    【解决方案2】:

    试试这样的

    this.eventsService.getUpcoming(id).pipe(
      switchMap((upcoming) => {
        if (upcoming.length) {
           return of(upcoming);
        }
        return this.eventsService.getCurrent(id)
      },
      switchMap((current) => {
         if (current.length) {
           return of(current);
         }
         return this.eventsService.getPast(id)
      })
    )
    

    这样你就不会嵌套switchMap

    【讨论】:

    • 是的,这是可行的,因为两个 switchMap 都进行相同的检查。
    【解决方案3】:

    您可以使用 concat 运算符来创建一个可观察对象,该可观察对象按顺序从每个可观察对象发出值。将结果通过管道传递给 find 运算符,该运算符将从满足条件的第一个结果返回结果并完成 observable。这将防止从 concat 创建的流中执行后续的 observables。

    先和先的区别

    我认为您会发现对您的示例有用的 find 的一个副作用是,如果不满足任何条件,则仍会发出最后一个结果。这与使用像 first 这样的运算符不同,如果源 observable 在没有匹配的情况下完成,则会抛出错误,或者 take 不会发出任何东西,因为先前的运算符会用于过滤排放。

    所以在你的情况下,如果所有响应都是空的,你至少会得到一个空数组。

    concat(
      // try each request in order.
      this.eventsService.getUpcoming(id),
      this.eventsService.getCurrent(id),
      this.eventsService.getPast(id)
    ).pipe(
      // emits the first result that meets the condition.
      find(response => response.length > 0) 
    );
    

    【讨论】:

      猜你喜欢
      • 2020-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多