30 天精通 RxJS(17): Observable Operators - switch, mergeAll, concatAll

今天我們要講三個 operators,這三個 operators 都是用來處理 Higher Order Observable。所謂的 Higher Order Observable 就是指一個 Observable 送出的元素還是一個 Observable,就像是二維陣列一樣,一個陣列中的每個元素都是陣列募寨。如果用泛型來表達就像是

Observable<Observable<T>>
通常我們需要的是第二層 Observable 送出的元素森缠,所以我們希望可以把二維的 Observable 改成一維的拔鹰,像是下面這樣

Observable<Observable<T>> => Observable<T>
其實想要做到這件事有三個方法 switch、mergeAll 和 concatAll贵涵,其中 concatAll 我們在之前的文章已經(jīng)稍微講過了列肢,今天這篇文章會講解這三個 operators 各自的效果跟差異。

Operators
concatAll
我們在講簡易拖拉的范例時就有講過這個 operator宾茂,concatAll 最重要的重點就是他會處理完前一個 observable 才會在處理下一個 observable,讓我們來看一個范例

var click = Rx.Observable.fromEvent(document.body, 'click');
var source = click.map(e => Rx.Observable.interval(1000));

var example = source.concatAll();
example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});
// (點擊后)
// 0
// 1
// 2
// 3
// 4
// 5 ...

JSBin

上面這段程式碼跨晴,當(dāng)我們點擊畫面時就會開始送出數(shù)值欧聘,如果用 Marble Diagram 表示如下

click  : ---------c-c------------------c--.. 
        map(e => Rx.Observable.interval(1000))
source : ---------o-o------------------o--..
                   \ \
                    \ ----0----1----2----3----4--...
                     ----0----1----2----3----4--...
                     concatAll()
example: ----------------0----1----2----3----4--..

從 Marble Diagram 可以看得出來端盆,當(dāng)我們點擊一下 click 事件會被轉(zhuǎn)成一個 observable 而這個 observable 會每一秒送出一個遞增的數(shù)值怀骤,當(dāng)我們用 concatAll 之后會把二維的 observable 攤平成一維的 observable,但 concatAll 會一個一個處理焕妙,一定是等前一個 observable 完成(complete)才會處理下一個 observable蒋伦,因為現(xiàn)在送出 observable 是無限的永遠不會完成(complete),就導(dǎo)致他永遠不會處理第二個送出的 observable!

我們再看一個例子

var click = Rx.Observable.fromEvent(document.body, 'click');
var source = click.map(e => Rx.Observable.interval(1000).take(3));

var example = source.concatAll();
example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});

現(xiàn)在我們把送出的 observable 限制只取前三個元素访敌,用 Marble Diagram 表示如下

click  : ---------c-c------------------c--.. 
        map(e => Rx.Observable.interval(1000))
source : ---------o-o------------------o--..
                   \ \                  \
                    \ ----0----1----2|   ----0----1----2|
                     ----0----1----2|
                     concatAll()
example: ----------------0----1----2----0----1----2--..

這裡我們把送出的 observable 變成有限的凉敲,只會送出三個元素寺旺,這時就能看得出來 concatAll 不管兩個 observable 送出的時間多么相近爷抓,一定會先處理前一個 observable 再處理下一個阻塑。

switch
switch 同樣能把二維的 observable 攤平成一維的蓝撇,但他們在行為上有很大的不同,我們來看下面這個范例

var click = Rx.Observable.fromEvent(document.body, 'click');
var source = click.map(e => Rx.Observable.interval(1000));

var example = source.switch();
example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});

用 Marble Diagram 表示如下

click  : ---------c-c------------------c--.. 
        map(e => Rx.Observable.interval(1000))
source : ---------o-o------------------o--..
                   \ \                  \----0----1--...
                    \ ----0----1----2----3----4--...
                     ----0----1----2----3----4--...
                     switch()
example: -----------------0----1----2--------0----1--...

switch 最重要的就是他會在新的 observable 送出后直接處理新的 observable 不管前一個 observable 是否完成渤昌,每當(dāng)有新的 observable 送出就會直接把舊的 observable 退訂(unsubscribe)虽抄,永遠只處理最新的 observable!

所以在這上面的 Marble Diagram 可以看得出來第一次送出的 observable 跟第二次送出的 observable 時間點太相近独柑,導(dǎo)致第一個 observable 還來不及送出元素就直接被退訂了迈窟,當(dāng)下一次送出 observable 就又會把前一次的 observable 退訂忌栅。

mergeAll
我們之前講過 merge 他可以讓多個 observable 同時送出元素车酣,mergeAll 也是同樣的道理索绪,它會把二維的 observable 轉(zhuǎn)成一維的湖员,并且能夠同時處理所有的 observable瑞驱,讓我們來看這個范例

var click = Rx.Observable.fromEvent(document.body, 'click');
var source = click.map(e => Rx.Observable.interval(1000));

var example = source.mergeAll();
example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});
上面這段程式碼用 Marble Diagram 表示如下

click  : ---------c-c------------------c--.. 
        map(e => Rx.Observable.interval(1000))
source : ---------o-o------------------o--..
                   \ \                  \----0----1--...
                    \ ----0----1----2----3----4--...
                     ----0----1----2----3----4--...
                     switch()
example: ----------------00---11---22---33---(04)4--...

從 Marble Diagram 可以看出來娘摔,所有的 observable 是并行(Parallel)處理的唤反,也就是說 mergeAll 不會像 switch 一樣退訂(unsubscribe)原先的 observable 而是并行處理多個 observable凳寺。以我們的范例來說拴袭,當(dāng)我們點擊越多下读第,最后送出的頻率就會越快拥刻。

另外 mergeAll 可以傳入一個數(shù)值,這個數(shù)值代表他可以同時處理的 observable 數(shù)量般哼,我們來看一個例子

var click = Rx.Observable.fromEvent(document.body, 'click');
var source = click.map(e => Rx.Observable.interval(1000).take(3));

var example = source.mergeAll(2);
example.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});

這裡我們送出的 observable 改成取前三個,并且讓 mergeAll 最多只能同時處理 2 個 observable惠窄,用 Marble Diagram 表示如下

click  : ---------c-c----------o----------.. 
        map(e => Rx.Observable.interval(1000))
source : ---------o-o----------c----------..
                   \ \          \----0----1----2|     
                    \ ----0----1----2|  
                     ----0----1----2|
                     mergeAll(2)
example: ----------------00---11---22---0----1----2--..

當(dāng) mergeAll 傳入?yún)?shù)后,就會等處理中的其中一個 observable 完成杆融,再去處理下一個。以我們的例子來說脾歇,前面兩個 observabel 可以被并行處理,但第三個 observable 必須等到第一個 observable 結(jié)束后藕各,才會開始池摧。

我們可以利用這個參數(shù)來決定要同時處理幾個 observable激况,如果我們傳入 1 其行為就會跟 concatAll 是一模一樣的作彤,這點在原始碼可以看到他們是完全相同的。

今日小結(jié)
今天介紹了三個可以處理 High Order Observable 的方法竭讳,并講解了三個方法的差異,不知道讀者有沒有收穫呢绢慢? 如果有任何問題歡迎在下方留言給我蹈丸,感謝呐芥!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逻杖,一起剝皮案震驚了整個濱河市思瘟,隨后出現(xiàn)的幾起案子荸百,更是在濱河造成了極大的恐慌滨攻,老刑警劉巖够话,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件光绕,死亡現(xiàn)場離奇詭異女嘲,居然都是意外死亡诞帐,警方通過查閱死者的電腦和手機欣尼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門停蕉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愕鼓,“玉大人慧起,你說我怎么就攤上這事菇晃◎炯罚” “怎么了磺送?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長估灿。 經(jīng)常有香客問我,道長脾歧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任鞭执,我火速辦了婚禮芒粹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘大溜。我一直安慰自己,他們只是感情好钦奋,可當(dāng)我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著付材,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厌衔。 梳的紋絲不亂的頭發(fā)上璧帝,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天富寿,我揣著相機與錄音睬隶,去河邊找鬼页徐。 笑死苏潜,一個胖子當(dāng)著我的面吹牛变勇,可吹牛的內(nèi)容都是我干的恤左。 我是一名探鬼主播贰锁,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼赃梧,長吁一口氣:“原來是場噩夢啊……” “哼豌熄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锣险,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎览闰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體压鉴,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年油吭,在試婚紗的時候發(fā)現(xiàn)自己被綠了署拟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡推穷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出类咧,到底是詐尸還是另有隱情,我是刑警寧澤痕惋,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站值戳,受9級特大地震影響议谷,放射性物質(zhì)發(fā)生泄漏述寡。R本人自食惡果不足惜柿隙,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一鲫凶、第九天 我趴在偏房一處隱蔽的房頂上張望禀崖。 院中可真熱鬧螟炫,春花似錦波附、人聲如沸昼钻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仅财。三九已至碗淌,卻和暖如春盏求,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亿眠。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纳像,地道東北人。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓竟趾,卻偏偏與公主長得像宫峦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子倦始,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容