如何用RxJS重构传统的同步循环?

如何用RxJS重构传统的同步循环?,rxjs,Rxjs,我是RxJS的新手,我正试着思考应该如何编写代码。我试图编写一个函数来扩展现有的http,它返回一个可观察的数据数组。然后我想在数组上循环,对每个对象发出http请求,并返回带有修改数据的新数组 以下是我目前掌握的情况: private mapEligibilitiesToBulk(bulkWarranties: Observable<any[]>): Observable<IDevice[]> { const warranties: IDevice[] = []

我是RxJS的新手,我正试着思考应该如何编写代码。我试图编写一个函数来扩展现有的http,它返回一个可观察的数据数组。然后我想在数组上循环,对每个对象发出http请求,并返回带有修改数据的新数组

以下是我目前掌握的情况:

private mapEligibilitiesToBulk(bulkWarranties: Observable<any[]>): Observable<IDevice[]> {
    const warranties: IDevice[] = [];
    bulkWarranties.subscribe((bulk: any[]) => {
      for (let warranty of bulk) {
        // Check if another device already has the information
        const foundIndex = warranties.findIndex((extended: IDevice) => {
          try {
            return warranty.device.stockKeepingId.equals(extended.part.partNumber);
          } catch (err) {
            return false;
          }
        });

        // Fetch the information if not
        if (foundIndex > -1) {
          warranty.eligibilityOptions = warranties[foundIndex];
        } else {
          this.getDevices(warranty.device.deviceId.serialNumber).subscribe((devices: IDevice[]) => {
            warranty = devices[0];
          }); // http request that returns an observable of IDevice
        }

        warranties.push(warranty);
      }
    });

    return observableOf(warranties);
  }
private mapelibilitystobulk(可观察的):可观察的{
常量保证:IDevice[]=[];
bulk.subscribe((bulk:any[])=>{
用于(批量保修){
//检查另一台设备是否已具有该信息
const foundIndex=保修。findIndex((扩展:IDevice)=>{
试一试{
退货保修.device.stockKeepingId.equals(扩展的.part.part号);
}捕捉(错误){
返回false;
}
});
//如果没有,请获取信息
如果(foundIndex>-1){
warranty.eligibilityOptions=保修[foundIndex];
}否则{
this.getDevices(warranty.device.deviceId.serialNumber)。订阅((设备:IDevice[])=>{
保修=设备[0];
});//返回IDevice的可观察值的http请求
}
保修。推送(保修);
}
});
返回可观察的(保证);
}

目前,我的代码立即返回一个可观察的数组,但是,它是空的,并且没有我想要的反应方式。任何建议或推荐阅读将不胜感激

如果不了解更多关于您的数据以及什么是有意义的,就不可能给出您需要的确切代码。然而,我做了一些假设,并将其放在一起,以展示一种可能的方法。这里的一个大假设是数据是可分组的,而您实际上试图实现的是仅对每个唯一的
保修.device.stockKeepingId
进行一次http调用

我将这段代码作为您的起点,希望它能让您更接近您想要实现的目标。根据StackBlitz,以下是相关方法:

public mapEligibilitiesToBulk(bulk: Warranty[]): Observable<IDevice[]> {
  return from(bulk).pipe(
    tap(warranty => console.log('in tap - warranty is ', warranty)),
    groupBy(warranty => warranty.device.stockKeepingId),
    mergeMap(group$ => group$.pipe(reduce((acc, cur) => [...acc, cur], []))),
    tap(group => console.log('in tap - group is ', group)),
    concatMap(group => this.getDevices(group[0].device.deviceId.serialNumber)),
    tap(device => console.log('in tap - got this device back from api: ', device)),
    toArray()
  )
}
public Mapelibilities Tobulk(批量:保修[]):可观察{
从(散装)管道返回(
tap(保修=>console.log('在tap中-保修为',保修)),
groupBy(保修=>warranty.device.stockKeepingId),
合并映射(组$=>组$.pipe(减少((acc,cur)=>[…acc,cur]),
点击(group=>console.log('in-tap-group is',group'),
concatMap(组=>this.getDevices(组[0].device.deviceId.serialNumber)),
点击(device=>console.log('in-tap-get this device from-api:',device'),
toArray()
)
}
有几件事需要注意:

  • 确保打开控制台查看结果
  • 我将第一个参数更改为数组,而不是可观察的,假设您需要一个完整的数组作为开始。让我知道,如果你想扩展一个现有的可观察的,这是很容易实现的
  • 我加入了一些tap()以便您可以看到代码在两个重要点上的作用
  • 在StackBlitz中,当前的
    getDevices()
    为每个调用返回相同的内容,我这样做是为了简化模拟,而不是因为我相信它会以这种方式工作。:)
您希望其他设备多久获取一次信息?有多少http请求是这样省略的?您认为什么更快(更可取):省略此http请求缩减,而是同时(或成批)发送所有http请求,而不是按顺序发送—或者—执行http请求缩减并按顺序发送减少的http请求量?如果您确实希望迭代循环,请查看rxjs函数。但我猜你最好还是看一下,也许可以按
保修.device.stockKeepingId
分组。其他提示:不要在订阅中订阅,事实上,我怀疑您不希望在这个函数中有任何订阅;希望创建数据流,让操作符函数为您工作,而不是所有这些命令代码;如果可能的话,试着只在一个地方订阅-建立一个可观察的链。