注意:
- flatMap 是 mergeMap 的別名。
- 如果一次只能啟用一個內部訂閱,請使用 switchMap.
- 如果內部 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 座標以及當前時間戳。
最後產生的輸出: