實務上常會將眾多 Observable 加以合併,concat()
除了會將 Observable 合併外,還會依照 Argument 順序合併,直到一個 Observable 完成,才會繼續合併下一個 Observable。
Version
macOS Catalina 10.15.5
WebStorm 2020.1.2
Vue 2.6.11
RxJS 6.5.5
concat()
按下 Show Message
後,會陸續顯示 Get Ready!
、3
、2
、1
、Go!
。
<template>
<div>
<button v-stream:click="click$">Show Message</button>
<div>{{ message$ }}</div>
</div>
</template>
<script>
import { concat, EMPTY } from 'rxjs'
import { startWith, delay, switchMapTo } from 'rxjs/operators'
let delayMsg$ = x => EMPTY.pipe(
startWith(x),
delay(1000)
)
let subscriptions = function() {
let slogan$ = concat(
delayMsg$('Get Ready!'),
delayMsg$(3),
delayMsg$(2),
delayMsg$(1),
delayMsg$('Go!')
)
let message$ = this.click$.pipe(
switchMapTo(slogan$)
)
return { message$ }
}
export default {
name:'App',
domStreams: [
'click$'
],
subscriptions
}
</script>
12 行
let delayMsg$ = x => EMPTY.pipe(
startWith(x),
delay(1000)
)
delayMsg()
負責由 argument 產生 message,由 EMPTY
Observable 開始建立,首先以 startWith()
建立 initial value,最後 delay 1s
才產生。
18 行
let slogan$ = concat(
delayMsg$('Get Ready!'),
delayMsg$(3),
delayMsg$(2),
delayMsg$(1),
delayMsg$('Go!')
)
陸續將要顯示的 Get Ready!
、3
、2
、1
與 Go!
傳給 delayMsg$()
產生 Observable。
由於 delayMsg$()
所產生的 Observable 都只 delay 1s
,理論上應該同時產生,為什麼最後卻是先後出現呢 ?
因為 concat()
會依照 argument 順序先後合併,且會等前一個 Observable 結束後,才會執行下一個 Observable。
concat()
將眾多 Observable 依 argument 順序合併
當 a
、b
Observabl 結束時,才會合併 x
、y
Observable。
26 行
let message$ = this.click$.pipe(
switchMapTo(slogan$)
)
由於 click$
是 Observable,要由 click$
引起 slogan$
會造成 Higher Order Observable,因此使用 switchMapTo()
攤平。
Conclusion
- 原本會以為要分別 delay 不同時間才能造成相同效果,但透過
concat()
,由於其完成前一個 Observable 才會執行下一個 Observable 特性,因此所有 Observable 只要 delay 相同時間即可