RxJS 系列 – Join Creation Operators

前言

我們一樣從簡單和常用的入手.

第一篇介紹了 Creation Operators

上一篇介紹了 Filter Operators 

這一篇來到 Join Creation Operators.

 

參考

Docs – Join Creation Operators

 

merge

merge 會同時 subscribe 所有的 Observable. 任何一個發佈都會接收.

const s1 = new Subject();
const s2 = new Subject();
merge(s1, s2).subscribe(v => console.log(v)); // s1..s2
s1.next('s1');
s2.next('s2');

merge 會創建出一個新的 Observable. 當被訂閱時, 它會去 subscribe s1 和 s2.

一旦 s1 或 s2 發佈, merge observable 也會隨之發佈. merge 的 subscriber 就會接收.

merge 常用來實現多種不同監聽, 但要做執行相同邏輯的場景.

比如 click submit button 或 keydown enter 都會執行 ajax search. 那麼我們就可以寫 merge(click$, enter$).subscrube(() => ajax());

 

combineLatest

combineLatest 和 merge 類似, 創建新的 Observable 並且訂閱所有 Observable

const s1 = new Subject();
const s2 = new Subject();
combineLatest([s1, s2]).subscribe(([v1, v2]) => console.log([v1, v2])); // [s1, s2]
s1.next('s1'); // 不會接收, 因爲 s2 還沒有值
s2.next('s2'); // 接收, 因爲 s1, s2 都有值了

但它和 merge 有 2 個區別

1. merge 每次只接收到 1 個值 (最新發布的那個), 而 combineLatest 會接收到所有 Observable 的值 (它是一個 Array, 因爲每一次發佈值都會被 cache 起來)

2. combineLatest 必須等到所有的 Observable 最少發佈一次以後, 纔會開始接收.

上面的例子中, s1.next('s1') 的時候, console 沒有響, 因爲 s2 這時還沒有任何發佈記入. 只有當 s2.next 以後, s1, s2 都有了發佈記入, console 才響, 同時獲取到了 s1, s2 的最新的值.

combineLatest 在開發中也是經常需要使用到的, 尤其是當我們要 merge 的效果, 同時希望它返回當前所有 Observable 最新值的時候.

以前遇過的坑

const s1 = new Subject();
combineLatest([s1, s1]).subscribe(v => console.log(v));
s1.next('value'); // [value, value]
s1.next('value2'); // [value2, value]..[value2, value2]

效果

雖然都是 s1, 但 combineLatest 會把它們當作不同的 Observable, 會有 2 個訂閱, 而 s1.next 就想等於 2 個 Obserable 都發布了值, 但依然是有順序的哦, 一前以後.

所以會出現 3 個 console. 第二個 console 的接收值是 ['value2', 'value'] 因爲第一個 Observable 發佈, 第二個用的是 cached value.

 

zip

zip 和 combineLatest 有點像, 它們都會接收到所有 Observable 最新的值. 只是接收的時機不一樣.

多個 Observable 發佈的次數往往是沒有規律的. 可能 o1 發佈了 5 次, o2 才 2 次.

combineLatest 它不管大家的次數, 只要任何一個 Observable 發佈, 那就把其它所有的值拉出來, 一起發佈出去.

zip 則講究次數, 只有當每一個 Observable 都達到相同次數, 它纔會把每一個 Observable 那一次數的值取出來, 一起發佈出去.

看下面這個例子

  const s1 = new Subject();
  const s2 = new Subject();
  combineLatest([s1, s2]).subscribe(v => console.log(v));
  s1.next('s1');
  s2.next('s2'); // [s1, s2]
  s1.next('s11'); // [s11, s2]
  s1.next('s12'); // [s12, s2]
  s1.next('s13'); // [s13, s2]
  s2.next('s21'); // [s13, s21]

  zip([s1, s2]).subscribe(v => console.log(v));
  s1.next('s1');
  s2.next('s2'); // [s1, s2]
  s1.next('s11');
  s1.next('s12');
  s1.next('s13');
  s2.next('s21'); // [s11, s21]

zip 最終 console 只響了 2 次. 而 combineLatest 響了 5 次.

雖然 s1 發佈了 5 次, 但 zip 要求所有 Observable 必須要有相同次數, 而 s2 只有 2 次, 所以最終只能發佈 2 次而已. 而第二次的發佈, s1 的 value 並不是它最新的 value 而是它第 2 次發佈的 value 哦.

 

concat

concat 和 merge 類似, 它會 subscribe 所有 Observable 但它不像 merge 那樣一開始就全部 subscribe. 它會挨個挨個去 subscribe. 當第一個 Observable complete 以後纔去 subscribe 第二個.

const s1 = new Subject();
const s2 = new Subject();
concat(s1, s2).subscribe(v => console.log(v));
s1.next('s1'); // 接收 s1
s2.next('s2'); // 沒接收, 因爲 s1 還沒有 complete, s2 還沒有開始 subscribe
s1.complete();
s2.next('s2'); // 接收 s2

 

forkJoin

forkJoin 好比 Promise.all, 當所有的 Observable complete 後, 它纔會接收, 並且得到所有 Observable 最終的值.

const s1 = new Subject();
const s2 = new Subject();
forkJoin([s1, s2]).subscribe(v => console.log(v)); // [s1, s2]
s1.next('s1');
s2.next('s2');
s1.complete();
s2.complete(); // 這時纔開始接收

 

race

race 就是比賽, 第一個發佈的 Observable 將保留訂閱, 其餘的就淘汰退訂

const s1 = new Subject();
const s2 = new Subject();
race([s1, s2]).subscribe(v => console.log(v)); // s2..s21
s2.next('s2'); // 接收
s1.next('s1'); // 不接收, 因爲 s2 勝出, s1 已經被退訂了
s2.next('s21'); // 接收 只有勝出的 s2 發佈纔會被接收

 

partition

partition 的作用是把 1 個 Observable 拆分成 2 個.

上一篇介紹 filter operator 時, 有寫過下面這個 odd, even 例子

const source = from([1, 2, 3, 4]);
const odd$ = source.pipe(filter(v => v % 2 !== 0));
const even$ = source.pipe(filter(v => v % 2 === 0));
odd$.subscribe(v => console.log(v)); // 1..3  
even$.subscribe(v => console.log(v)); // 2..4

它可以用 partition 改寫成

const [odd$, even$] = partition(source, v => v % 2 !== 0);

條件 true 表示它屬於第一個 Observable, false 則進入第二個 Observable.

 

一句話總結

merge : 任何一個發佈, 接收最新發布值

combineLatest : 任何一個發佈, 接收所有最新的值 (開始接收條件: 所有 Observable 最少要有一次發佈)

zip : 和 combineLatest 一樣, 但它 care Observable 發佈的次數.當所有 Observable 都滿足 n 次的時候發佈, 接收第 n 次所有的值.

concat : 上一個 Observable complete 了才 subscribe 下一個

forkJoin: Promise.all, 所有 Observable complete 後, 接收所有最終的值

race : 第一個發佈的 Observable 繼續訂閱, 退訂其餘的 Observale

partition : 通過 if else 把一個 Observable 拆分成 2 個

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章