【问题标题】:How to chain switchMap-operators with function bodies in rxjs 6如何在 rxjs 6 中将 switchMap-operators 与函数体链接起来
【发布时间】:2020-03-31 11:18:07
【问题描述】:

我有一个使用 ionic 和 angular 构建的移动应用程序,我想将其从 rxjs 5.5 升级到 rxjs 6。但是,rxjs 使用运算符的方式似乎存在一些重大变化,尤其是在返回值的方式上一个 switchMap 运算符在管道链中的下一个运算符中处理。这在迁移文档 (https://rxjs-dev.firebaseapp.com/guide/v6/migration) 中并不清楚,我找不到解决方法。

问题可能在于我在 switchMap-operators 中使用了函数体。该方法基于较旧的 Internet 资源,但我在最近的示例中很少看到它,并且不确定它是否仍然应该使用。

我需要这种方法的原因是,我使用 observables 的方式或多或少是作为 Promise 的替代品——这是一种确保不同步骤按顺序运行的方式。因此,没有一个单一的数据流贯穿运营商,但任何运营商都可能是一种新型事件的开始。这是过去做出的决定,以防止可观察对象和承诺之间不断转换。现在看来,这可能不是一个好习惯,但就目前而言,如果可能的话,我宁愿保持原样。

不管怎样,还是以下面的为例:

initializeStatisticsObs(): Observable<any> {
    return this.speciesService.getImagesSizeInBytesObs()
      .pipe(
        switchMap((fSizeInBytes: number) => {
          this.imagesSizeInBytes = fSizeInBytes;
          return this.speciesService.getImagesNumberOfItemsObs();
        }),
        switchMap((fNumberOfItems: number) => {
          this.imagesNumberOfItems = fNumberOfItems;
          return of({});
        }),
..
      )
  }

  getImagesSizeInBytesObs(): Observable<number> {
    return this.speciesLocalStorageService.getSizeInBytesObs();
  }

  getImagesNumberOfItemsObs(): Observable<number> {
    return this.speciesLocalStorageService.getNumberOfItemsObs();
  }

如您所见,更高级别的函数 initializeStatisticsObs() 调用了另外两个函数,它们都返回一个数字,包装在一个 Observable 中。这两个数字最终都应该存储在 number 类型的变量中。我知道在这种情况下,异步运行的整个想法似乎并没有什么意义,但这只是一个简化的示例。

所以对 this.speciesService.getImagesSizeInBytesObs() 的调用是在管道链之外调用的,它的输出在第一个 switchMap 中被拾取,并存储在一个类型为 number 的变量中。

然后调用第二个类似的函数 this.speciesService.getImagesNumberOfItemsObs(),它再次返回一个包裹在 Observable 中的数字。第二个调用应该由第二个 switchMap 操作符接收,并再次存储在 number 类型的变量中。

这种方法在 rxjs 5.5 中运行良好,但在 6.4.0 或更高版本中出现构建错误。问题是显然 switchMap-operator 现在添加了一个额外的 Observable 包装器,因此第二个 switchMap 将&lt;Observable&lt;number&gt;&gt; 类型的值作为输入,与 this.imagesNumberOfItems 的数字类型冲突。

我得到的构建错误如下所示:

    Argument of type 'OperatorFunction<number, Observable<{}>>' is not assignable to parameter of type
    'OperatorFunction<Observable<number>, Observable<{}>>'. Type 'number' is not assignable to type
    'Observable<number>'.

我之所以认为使用函数体是问题的原因是当我使用这个时:

 initializeStatisticsObs(): Observable<any> {
    return this.speciesService.getImagesSizeInBytesObs()
      .pipe(
        switchMap((fSizeInBytes: number) => of(23)),
        switchMap((fNumberOfItems: number) => {
          this.imagesNumberOfItems = fNumberOfItems;
          return of({});
        })
 ..
      )
  }

效果很好。

顺便说一句,tap() 运算符可以与函数体一起使用而没有这些问题,但它们不适合我的目的。 有没有办法解决这个问题?

【问题讨论】:

    标签: angular rxjs rxjs6


    【解决方案1】:
    switchMap((fSizeInBytes: number) => {
          this.imagesSizeInBytes = fSizeInBytes;
          return this.speciesService.getImagesNumberOfItemsObs();
        })
    

    switchMap 返回 Observable 和 getImagesNumbersOfItemsObs 返回 Observable 所以你的回报是 Observable>

    你应该在这里使用点击

    tap((fSizeInBytes: number) => this.imagesSizeInBytes = fSizeInBytes)
    switchMap(() => this.speciesService.getImagesNumberOfItemsObs())
    tap((fNumberOfItems: number) => this.imagesNumberOfItems = fNumberOfItems))
    

    但最好在此处使用 forkJoin 运算符,并期望您的值在订阅中作为数组

    【讨论】:

    • 太好了,点击方法有效,实际上很简单。这也是我现在拥有的最简单的迁移路径。稍后我会考虑 forkJoin。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    • 2022-06-26
    • 2019-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多