【发布时间】: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 将<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() 运算符可以与函数体一起使用而没有这些问题,但它们不适合我的目的。 有没有办法解决这个问题?
【问题讨论】: