由於感受對這幾個觀察者映射理解不夠充分,因此找到了一個神奇的網站。它能夠幫助你充分分辨這些 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中的幾個概念。下面是一些參考文檔和工具。