RxJava 中的 flatmap 和 switchmap 有什么区别?

What is the difference between flatmap and switchmap in RxJava?

rxjava doc definition of switchmap is rather vague and it links to the same page as flatmap。这两个运算符有什么区别?

根据文档 (http://reactivex.io/documentation/operators/flatmap.html)

switchMap 类似于 flatMap 它只会从新的可观察对象发出项目,直到从源可观察对象发出新事件.

大理石图很好地说明了这一点。 请注意图中的差异:

switchMap中,第二个原始发射(绿色大理石)不发射其第二个映射 emission (green square), 自第三次 original emission (blue marble)已经开始并已经发射了第一个 mapped 发射(blue diamond)。换句话说,只有 first 两个 mapped 绿色排放发生;没有发出绿色方块,因为蓝色钻石击败了它。

flatMap 中,将发出所有映射的结果,即使它们是 "stale"。换句话说,两个第一个第二个映射绿色排放发生——green square 会被发射(如果他们使用一致的地图函数;因为他们没有,你会看到 second 绿色菱形,即使它被发射 after first blue diamond)

switchMap

flatMap

我在实施 "instant search" 时遇到了这个问题 - 即当用户在文本框中键入内容时,每次击键都会近乎实时地显示结果。解决方案似乎是:

  1. 有主题,比如String的PublishSubject
  2. 在文本框更改回调中,调用.onNext(text)
  3. 将 .debounce 过滤器应用于速率限制服务器查询
  4. 应用 .switchMap 执行服务器查询 - 获取搜索词并返回 SearchResponse 的 Observable
  5. 使用使用 SearchResponse 并更新 UI 的方法申请 .subscribe。

使用 flatMap 时,搜索结果可能会过时,因为返回的搜索响应可能会乱序。要解决此问题,应使用 switchMap,因为它确保在提供新的可观察对象后取消订阅旧的可观察对象。

因此,总而言之,当所有结果都很重要时应该使用 flatMap,而不管它们的时间如何,而当只有最后一个 Observable 的结果很重要时应该使用 switchMap。

switchMap was once called flatMapLatest 在 RxJS 4.

它基本上只是传递来自最新 Observable 的事件并取消订阅前一个。

没有与 switchMapconcatMapconcatMapEager 进行比较和对比的 flatMap 讨论是不完整的。

所有这些方法都采用 Func1 将流转换为 Observable 然后发出;区别在于 returned Observables 何时被订阅和取消订阅,以及这些 Observables 的排放是否以及何时由相关 ____Map 运营商排放.

  • flatMap 订阅尽可能多的发出的 Observable。 (这是一个依赖于平台的数字。例如 Android 上的一个较小的数字)当顺序不重要并且您希望尽快排放时使用它。
  • concatMap 订阅第一个 Observable 并且仅在前一个完成后订阅下一个 Observable。当顺序很重要并且您想节省资源时使用此选项。一个完美的例子是通过首先检查缓存来推迟网络调用。通常后跟 .first().takeFirst() 以避免做不必要的工作。

    http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

  • concatMapEager 的工作原理大致相同,但会订阅尽可能多的订阅(取决于平台),但只会在前一个 Observable 完成后才会发出。当你有很多并行处理需要完成,但(不像 flatMap)你想保持原来的顺序时是完美的。

  • switchMap 将订阅它遇到的最后一个 Observable 并取消订阅所有之前的 Observable。这对于搜索建议这样的情况来说是完美的:一旦用户改变了他们的搜索查询,旧的请求就不再有任何意义,所以它被取消订阅,一个表现良好的 Api 端点将取消网络请求。

如果您 returning Observable 没有 subscribeOn 另一个线程,则上述所有方法的行为可能大致相同。当您允许嵌套的 Observables 在它们自己的线程上运行时,就会出现有趣且有用的行为。然后你可以从并行处理中获得很多好处,智能地取消订阅或不订阅你不感兴趣的Subscribers

Observables
  • amb 可能也很有趣。给定任意数量的 Observable,它发出与第一个发出任何东西的 Observable 相同的项目。 当您有多个源 could/should return 相同的东西并且您想要性能时,这可能很有用。例如排序,您可以 amb 使用合并排序进行快速排序,然后使用更快的一个。

如果您正在寻找示例代码

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

您可以在此处查看更多示例https://github.com/politrons/reactive

这是另一个 - 101 行长 example。这为我解释了事情。

正如所说:它获取最后一个可观察到的(如果你愿意的话,最慢的一个)并忽略其余的。

结果:

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

你看 A 被忽略了。

Map、FlatMap、ConcatMapSwitchMap 应用函数或修改 Observable 发出的数据。

  • Map 修改源 Observable 发射的每个项目并发射修改后的项目。

  • FlatMap、SwitchMapConcatMap 也对每个发出的项目应用一个函数,而不是返回修改后的项目,它 returns Observable 本身可以再次发射数据。

  • FlatMapConcatMap 的工作几乎相同。它们合并由多个 Observable 和 returns 单个 Observable 发出的项目。

  • FlatMapConcatMap 之间的区别在于项目的发射顺序。
  • FlatMap 可以在发射时交错项目,即发射的项目顺序不会保持不变。
  • ConcatMap 保留项目的顺序。但 ConcatMap 的主要缺点是,它必须等待每个 Observable 完成其工作,因此无法保持异步。
  • SwitchMapFlatMapConcatMap 有点不同。 SwitchMap 在新项目开始发射时取消订阅先前的源 Observable,因此总是从当前 Observable 发射项目。