Rxjs mergeMap 的使用場合

注销發表於2022-05-22

注意:

  1. flatMap 是 mergeMap 的別名。
  2. 如果一次只能啟用一個內部訂閱,請使用 switchMap.
  3. 如果內部 observables 的發射和訂閱順序很重要,請使用 concatMap.

當需要展平內部 observable 但想要手動控制內部訂閱的數量時,是 mergeMap 極佳的使用場合。

例如,當使用 switchMap 時,每個內部訂閱在源發出時完成,即任意時間段只允許一個活動的內部訂閱。相比之下,mergeMap 允許同時啟用多個內部訂閱。因此,mergeMap 最常見的用例之一是不應取消的請求,這些請求被認為是寫入而不是讀取。

一個典型的例子就是 SAP 電商雲購物車裡不同行專案的金額,可以並行地進行增減操作。

請注意,如果這些寫入必須保持順序,則 concatMap 是更好的選擇。比如資料庫的寫操作。

由於 mergeMap 一次維護多個活動的內部訂閱,因此可能會由於長期存在的內部訂閱造成記憶體洩漏。一個基本的例子是,如果使用內部計時器或 dom 事件流對映到可觀察物件。在這些情況下,如果仍然希望使用 mergeMap,一個好辦法是利用另一個運算子來管理內部訂閱的完成,比如考慮 take 或 takeUntil。當然還可以使用 concurrent 引數限制一次活動內部訂閱的數量。

看一個例子:

import { fromEvent, of } from 'rxjs';
import { mergeMap, delay } from 'rxjs/operators';

// faking network request for save
const saveLocation = location => {
  return of(location).pipe(delay(500));
};
// streams
const click$ = fromEvent(document, 'click');

click$
  .pipe(
    mergeMap((e: MouseEvent) => {
      return saveLocation({
        x: e.clientX,
        y: e.clientY,
        timestamp: Date.now()
      });
    })
  )
  // Saved! {x: 98, y: 170, ...}
  .subscribe(r => console.log('Saved!', r));

saveLocation 是一個函式,它能把任何傳入的輸入引數,包裹成一個 Observable,並且這個 Observable 並不是立即 emit 資料,而是延遲 500 毫秒。

mergeMap 接收一個函式作為輸入引數,這個函式的輸入引數就是透過 pipe 連結 mergeMap 的 Observable 裡包含的元素,即 MouseEvent;project 返回的資料型別是一個新的 Observable,包含了螢幕點選的 X 和 Y 座標以及當前時間戳。

最後產生的輸出:

相關文章