【问题标题】:Avoiding nested Rx subscription calls - what is the reasoning?避免嵌套的 Rx 订阅调用 - 原因是什么?
【发布时间】:2021-03-01 19:14:48
【问题描述】:

我知道使用 Rx 的 flatmap 或 flatmapLatest 比嵌套订阅更可取。但是,我找不到令人信服的理由说明嵌套订阅调用“应该不惜一切代价避免”(RxSwift Github Tips),并且想了解原因。

除了“不良代码气味”之外,对具体问题有任何见解吗?

示例 (source):

使用嵌套订阅(错误)

textField.rx.text.subscribe(onNext: { text in
    performURLRequest(text).subscribe(onNext: { result in
        ...
    })
    .disposed(by: disposeBag)
})
.disposed(by: disposeBag)

使用 flatmapLatest(好)

textField.rx.text
    .flatMapLatest { text in
        // Assuming this doesn't fail and returns result on main scheduler,
        // otherwise `catchError` and `observeOn(MainScheduler.instance)` can be used to
        // correct this.
        return performURLRequest(text)
    }
    ...
    .disposed(by: disposeBag) // only one top most disposable

【问题讨论】:

    标签: ios swift system.reactive rx-swift


    【解决方案1】:

    在这种特殊情况下,不好的示例可能会产生过时的结果 - 当textField 更新并触发新查询时,没有什么可以防止产生对performURLRequest 的过时响应。

    当然,这取决于您的用例,但根据过时的 textField 值显示结果(例如搜索结果)通常是错误的。更糟糕的是,可能会发生较早的 URLRequest 运行缓慢并在 之后返回,从而无限期地显示不正确的结果。

    相比之下,flatMapLatest 确保在 textField 更新后立即取消订阅来自先前值的待处理结果流,从而防止处理过时的结果。

    此并发问题是通过使用单个流通常可以实现更好的协调和效率的一个示例。

    它还使订阅管理更加清晰,并且您不太可能无法正确清理。

    【讨论】:

    • 处置订单大+1。在前一种情况下,您最终可能会在 外部订阅被释放之后调用内部订阅的闭包。 flatMap 不会发生这种情况。
    【解决方案2】:

    我认为首先要注意的是您的两个示例的行为不同。第一个将在每次文本字段更改时发出网络请求不会取消先前的请求。在后一种情况下,当文本发生变化时,先前的请求(如果有)会被取消并开始新的请求。

    如果后一个示例使用 flatMap 而不是 flatMapLatest,它们会更相似,但请注意,这是前一种情况下 url 请求可以组合的唯一方法。在后一种情况下,您可以使用 flatMapLatest 确保取消旧请求(或 flatMapFirst 在请求正在进行时忽略事件,或 concatMap 存储事件直到前一个请求完成。)使用 flatMap更加灵活。

    就个人而言,我确实在少数选择情况下嵌套订阅。例如,当我要忽略内部订阅的事件(甚至不捕获其 Disposable)或设置异步循环构造时。

    【讨论】:

      猜你喜欢
      • 2023-01-30
      • 2018-11-27
      • 2020-05-31
      • 2022-08-25
      • 2020-08-18
      • 2019-10-03
      • 1970-01-01
      • 2023-01-11
      • 2022-06-22
      相关资源
      最近更新 更多