RxSwift顺序flatMap与Moya请求

时间:2018-04-19 09:16:10

标签: swift rx-swift reactivex moya

我目前有以下代码

func updateItems(_ observable: Observable<ContainingEntity>) -> Observable<ContainingEntity>{
    return observable
        .concatMap({ (containingEntity) -> Observable<ContainingEntity> in
            guard let itemEntity = orderEntity.itemEntity,
                itemEntity.name.count == 0 else{
                    return Observable.just(entity)
            }

            print("Need to fetch name of item #\(itemEntity.id)")

            return RestManager.getDetailOf(item: itemEntity)
                .flatMap({ (updatedItemEntity) -> Observable<ContainingEntity> in
                    var updatedContainingEntity = containingEntity
                    containingEntity.itemEntity = updatedItemEntity
                    print("Fetched item name: \(itemEntity.name)")
                    return Observable.just(containingEntity)
                })
        })
}

基本上,我需要确保每个 ContainingEntity itemEntity 都有一个名称,如果没有,请用Moya请求。

但我面对两张照片中的以下类型的输出:

  • 需要提取项目#1的名称
  • 需要提取项目#2的名称
  • 需要提取项目#3的名称
  • 提取项目名称:Name1
  • 提取项目名称:Name2
  • 提取项目名称:Name3

意味着我的concatMap中的操作是并行执行的,我不想要因为请求冗余和一些缓存系统我没有在这里显示:我可以有30倍相同的项ID和我不想要30次。

我期待的是:

  • 需要提取项目#1的名称
  • 提取项目名称:Name1
  • 需要提取项目#2的名称

  • 提取项目名称:Name2

  • 需要提取项目#3的名称
  • 提取项目名称:Name3

如何解决此问题?非常感谢你的帮助。

更新

我现在正在使用某种简单的缓冲区,这样可以节省需要更新的 ItemEntities ,并将这些项目分配给具有相同项目标识符的下一个 ContainingEntities 。这可以防止Moya多次执行相同的请求。

它完美无缺,但我不太喜欢RX外部这种机制的想法......

1 个答案:

答案 0 :(得分:1)

我认为使用VariableBehaviorSubject来控制顺序加载可能会起作用(下面的代码)。

但是您可能想重新考虑加载体系结构,因为使用此代码时,加载时间可能不是最佳的。

限制同时并行请求的数量可能属于其他组件,例如您的网络层。

我没有测试下面的代码,因此它甚至可能无法编译 - 如果有效,请告诉我并接受答案。

func updateItems(_ observable: Observable<ContainingEntity>) -> Observable<ContainingEntity>{
  let trigger = BehaviorSubject<Int>(value: 0)
  let sequential = Observable.zip(observable, trigger) { return $0.0 }
  return sequential
    .concatMap({ (containingEntity) -> Observable<ContainingEntity> in
      guard let itemEntity = orderEntity.itemEntity,
        itemEntity.name.count == 0 else{
          return Observable.just(entity)
      }

      print("Need to fetch name of item #\(itemEntity.id)")

      return RestManager.getDetailOf(item: itemEntity)
        .flatMap({ (updatedItemEntity) -> Observable<ContainingEntity> in
          var updatedContainingEntity = containingEntity
          containingEntity.itemEntity = updatedItemEntity
          print("Fetched item name: \(itemEntity.name)")
          trigger.onNext(0)
          return Observable.just(containingEntity)
        })
    })
}