简单理解 mergeMap, switchMap, concatMap, exhaustMap

由于感受对这几个观察者映射理解不够充分,因此找到了一个神奇的网站。它能够帮助你充分分辨这些 map。javascript

首先咱们以这两个源为标准。java

A:typescript

0 1 2 B:bash

10 10 10 如今,咱们把A和B两个源作一个 乘法操做,也就是源A的每个输出,都跟源B的每个输出作乘法。app

首先咱们定义一下咱们的源。dom

const { interval} = Rx;
const { take, map } = RxOperators;

const sourceA = (time) => interval(time).pipe(take(3));
const sourceB = (time, value) => interval(time).pipe(
  take(3),
  map(() => value * 10)
)
复制代码

mergeMap

为了研究 mergeMap 是怎么运做的,咱们能够经过如下代码来工做:svg

sourceA(1000).pipe(
  mergeMap((value) => sourceB(1500, value))
)

复制代码

把上面的代码复制到神奇的网站上,你就能够观察到,它是这样工做的。以后的代码也是经过这种方式展现的。工具

0 10 0 20 10 0 20 10 20 咱们能够看到,这样看可能不太直观,可是咱们将他们分别打印,你就能看出区别了:网站

10 10 10 0 1 2 要理解 mergeMap,第一点就是,它会直到两个源都输出数据的时候才会输出。那么,当源A输出后,须要等 1.5s 的时间等待源B的输出。然后,源A每隔1s就会有下一个输出,源B每隔1.5s后就会有下一个输出,因此,咱们能够看到,为了保证后面的时序不被打乱,mergeMap 把合成以后的输出分别按照源A和源B的时序输出了。ui

以源A的角度看,它的每个输出和源B的三个输出结合的输出的时序是源B的;以源B的角度看,它的每个输出和源A的三个输出结合的输出的时序是源A的。 因此mergeMap的做用是保证输出后的原有叠加的时序不变。

switchMap

到了switchMap,咱们能够看看输入到网站的代码。

sourceA(1000).pipe(
  switchMap((value) => sourceB(1500, value))
);
复制代码

而后,看看它的输出是怎么样的。

20 20 20

诶,怎么只有这么源A和源B的三个输出结合的输出?改一下时间,咱们把源B的时间改为 800ms,再来看看。

0 10 20 20 20

好了,看到源A的前两个输出只和源B结合了一次,源A的最后一个输出却都结合了。咱们仍是看看他们分别的输出。

0 1 2

源 A 输出

10 10 10

源 B 输出
咱们能够对比看出,每当源A发出一个新的输出,以前源A跟源B结合的输出都被截断。那么,能够看出源B的每次输出与源A的输出结合的输出都依赖于源A的时序,当源A发出新输出的时候,以前结合的全部未完成输出都会被截断。

因此,这也解释了,为何第一次源A只有最后一次的输出与源B结合。由于,源B每次输出的时序用时为1500ms,这个用时大于源A输出的用时。因此,当源A发出的第一次的输出准备与源B结合时(此时,源A须要等待源B运行完),源A的第二次的输出也发出了,因为switchMap的截断机制,便会跳过源A第一次的结合,以此类推。

concatMap

惯例,咱们仍是看看代码。

sourceA(500).pipe(
  concatMap((value) => sourceB(1000, value))
);
复制代码

下面是 concatMap 的输出。

0 0 0 10 10 10 20 20 20

咱们能够看到,concatMap 并不会截断,它跟mergeMap的输出内容同样,都是会把全部结合都输出。可是有一点,concatMap 输出结合的方式又跟mergeMap不太同样,它会等待上一次结合输出完毕后,才进行下一次的结合输出。也就是当 0,0,0 输出完毕后,才会输出 10,10,10。在这里, 时序会遵循如下规则,若是源B结合完了源A的数据,源A仍未发送下一条数据,源B将会等到源A的下一条数据的到来。若是源A的数据有堆积(或者A的时序比B的时序小),而源B仍未结合完,那么将会以源B的时序进行下一组结合。

exhaustMap

仍是惯例,这是最后一个了,看看代码吧。

sourceA(1000).pipe(
  exhaustMap((value) => sourceB(500, value))
);
复制代码

下面是 exhaustMap的输出。

0 0 0 20 20 20

能够看到,10 这个输出被截断了,它跟concatMap的区别就是,源A与源B的结合输出完毕后,并不会等待下一组结合的输出。若是在第一组结合输出完毕前,第二组结合就要开始输出的时候,exhaustMap会阻止第二组结合的输出,直到第一组结合彻底输出完毕。

这样,咱们不妨假设在它们开始输出的时候为第0秒,源A与源B的第一组结合彻底输出,须要耗费 1.5秒的时间,也就是它会在第1.5秒处彻底输出。而源A的第二组结合会在第1秒输出,因为exhaustMap的特性,第二组结合将不会发生,由于,1.5秒大于1秒。而第一组结合彻底输出后,第三组结合会在第三秒输出,这样便会输出 20,20,20。

总结

本文主要是帮助你深刻理解RxJs中的几个概念。下面是一些参考文档和工具。

Rxjs 官方文档

Rxjs 可视化工具

相关文章
相关标签/搜索