运行 连续 3 个 observable,在最后一个中使用第一个的结果

Run 3 observables sequentially, using result from first in the last one

上下文

我想 运行 使用 RxSwift 按顺序进行 3 个不同的操作:

  1. 获取产品
  2. 产品获取完成后,删除缓存
  3. 缓存删除完成后,使用步骤 1
  4. 中的产品保存新缓存

这些是我的服务中的函数定义:

struct MyService {

  static func fetchProducts() -> Observable<[Product]> {...}
  static func deleteCache() -> Observable<Void> {...}
  static func saveCache(_ products: [Product]) -> Observable<Void> {...}

}

我通常使用 flatMapLatest 实现该行为。

但是,我会用这种方法丢失第一个可观察对象 ([Product]) 的结果,因为中间的操作 (deleteCache) 不接收参数并且 returns 完成后作废。

struct CacheViewModel {


  static func refreshCache() -> Observable<Void> {
    return MyService.fetchProducts()
      .flatMapLatest { lostProducts in MyService.deleteCache() }
      .flatMapLatest { MyService.saveCache([=12=]) } // Compile error*
  }
  // * Cannot convert value of type 'Void' to expected argument type '[Product]'

}

编译错误是绝对公平的,因为中间的操作 'breaks' 第一个结果的传递链。

问题

有什么机制可以用 RxSwift 实现这种串行执行,累积先前操作的结果?

最简单的解决方案是,在第二个 flatMap() 中使用 Rx 框架 just 中的静态方法 return 一个类型为 Observable<Products> 的新 Observable,传入您在平面图闭包中捕获的 lostProducts,即:

static func refreshCache() -> Observable<Void> {
    return MyService.fetchProducts()
      .flatMapLatest { lostProducts -> Observable<[Product]> in 
        MyService.deleteCache()
        return Observable.just(lostProducts)
    }
      .flatMapLatest { MyService.saveCache([=10=]) } // No compile error
  }

这样你就不会丢失 flatMap 中第一次调用的结果,而只是在清除缓存后传递它。

您可以使用do(onNext:)删除缓存数据,然后在flatMapLatest中您可以保存产品。可选 SaveCacheDeleteCache 应该 return Completable 以便您可以在保存或删除操作失败时处理错误。

struct CacheViewModel {

    static func refreshCache() -> Observable<Void> {
        return MyService.fetchProducts()
            .do(onNext: { _ in
                MyService.deleteCache()
            }).flatMap { products in
                MyService.saveCache(products)
            }
    }
}
        service
            .fetchProducts()
            .flatMap { products in
                return service
                    .deleteCache()
                    .flatMap {
                       return service
                        .saveCache(products)
                    }
            }