由于感受对这几个观察者映射理解不够充分,因此找到了一个神奇的网站。它能够帮助你充分分辨这些 map。javascript
首先咱们以这两个源为标准。java
A:typescript
B:bash
如今,咱们把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
是怎么运做的,咱们能够经过如下代码来工做:svg
sourceA(1000).pipe(
mergeMap((value) => sourceB(1500, value))
)
复制代码
把上面的代码复制到神奇的网站上,你就能够观察到,它是这样工做的。以后的代码也是经过这种方式展现的。工具
咱们能够看到,这样看可能不太直观,可是咱们将他们分别打印,你就能看出区别了:网站
要理解 mergeMap,第一点就是,它会直到两个源都输出数据的时候才会输出。那么,当源A输出后,须要等 1.5s 的时间等待源B的输出。然后,源A每隔1s就会有下一个输出,源B每隔1.5s后就会有下一个输出,因此,咱们能够看到,为了保证后面的时序不被打乱,mergeMap 把合成以后的输出分别按照源A和源B的时序输出了。ui
以源A的角度看,它的每个输出和源B的三个输出结合的输出的时序是源B的;以源B的角度看,它的每个输出和源A的三个输出结合的输出的时序是源A的。 因此mergeMap的做用是保证输出后的原有叠加的时序不变。
到了switchMap,咱们能够看看输入到网站的代码。
sourceA(1000).pipe(
switchMap((value) => sourceB(1500, value))
);
复制代码
而后,看看它的输出是怎么样的。
诶,怎么只有这么源A和源B的三个输出结合的输出?改一下时间,咱们把源B的时间改为 800ms,再来看看。
好了,看到源A的前两个输出只和源B结合了一次,源A的最后一个输出却都结合了。咱们仍是看看他们分别的输出。
因此,这也解释了,为何第一次源A只有最后一次的输出与源B结合。由于,源B每次输出的时序用时为1500ms,这个用时大于源A输出的用时。因此,当源A发出的第一次的输出准备与源B结合时(此时,源A须要等待源B运行完),源A的第二次的输出也发出了,因为switchMap的截断机制,便会跳过源A第一次的结合,以此类推。
惯例,咱们仍是看看代码。
sourceA(500).pipe(
concatMap((value) => sourceB(1000, value))
);
复制代码
下面是 concatMap 的输出。
咱们能够看到,concatMap 并不会截断,它跟mergeMap的输出内容同样,都是会把全部结合都输出。可是有一点,concatMap 输出结合的方式又跟mergeMap不太同样,它会等待上一次结合输出完毕后,才进行下一次的结合输出。也就是当 0,0,0 输出完毕后,才会输出 10,10,10。在这里, 时序会遵循如下规则,若是源B结合完了源A的数据,源A仍未发送下一条数据,源B将会等到源A的下一条数据的到来。若是源A的数据有堆积(或者A的时序比B的时序小),而源B仍未结合完,那么将会以源B的时序进行下一组结合。
仍是惯例,这是最后一个了,看看代码吧。
sourceA(1000).pipe(
exhaustMap((value) => sourceB(500, value))
);
复制代码
下面是 exhaustMap的输出。
能够看到,10 这个输出被截断了,它跟concatMap的区别就是,源A与源B的结合输出完毕后,并不会等待下一组结合的输出。若是在第一组结合输出完毕前,第二组结合就要开始输出的时候,exhaustMap会阻止第二组结合的输出,直到第一组结合彻底输出完毕。
这样,咱们不妨假设在它们开始输出的时候为第0秒,源A与源B的第一组结合彻底输出,须要耗费 1.5秒的时间,也就是它会在第1.5秒处彻底输出。而源A的第二组结合会在第1秒输出,因为exhaustMap的特性,第二组结合将不会发生,由于,1.5秒大于1秒。而第一组结合彻底输出后,第三组结合会在第三秒输出,这样便会输出 20,20,20。
本文主要是帮助你深刻理解RxJs中的几个概念。下面是一些参考文档和工具。