如何在 rxjs 6 中将 switchMap 运算符与函数体链接起来

How to chain switchMap-operators with function bodies in rxjs 6

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

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

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

总之,以下面为例:

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() 调用了另外两个函数,它们都是 return 一个数字,包装在一个 Observable 中。这两个数字最终都应该存储在数字类型的变量中。我知道在这种情况下 运行 异步的整个想法似乎没有意义,但这只是一个简化的例子。

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

然后调用第二个类似的函数 this.speciesService.getImagesNumberOfItemsObs(),它再次 return 是一个包裹在 Observable 中的数字。第二个调用应由第二个 switchMap 运算符拾取并再次存储在类型为 number 的变量中。

此方法在 rxjs 5.5 中运行良好,但在 6.4.0 或更高版本中出现构建错误。问题是显然 switchMap-operator 现在添加了一个额外的 Observable 包装器,因此第二个 switchMap 得到一个 <Observable<number>> 类型的值作为输入,与 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() 运算符可以与函数体一起使用而不会出现这些问题,但它们不适合我的目的。 有办法解决这个问题吗?

switchMap((fSizeInBytes: number) => {
      this.imagesSizeInBytes = fSizeInBytes;
      return this.speciesService.getImagesNumberOfItemsObs();
    })

switchMap return Observable 和 getImagesNumbersOfItemsObs return Observable 所以你的 return 是 Observable>

你应该在这里使用点击

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

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