mergeMap (flatMap)
Projects each source value to an observable and merges all inner observables.
Unlike switchMap, does not cancel previous inner observables.
Marble Diagram
Section titled “Marble Diagram”mergeMap(fn)
Example
Section titled “Example”// Timeline://// input$ A B C// inner A A1 A2 A3// inner B B1 B2 B3// inner C C1 C2 C3// result$ A1 A2 A3 B1 B2 C1 B3 C2 C3//// Explanation:// - mergeMap creates an inner observable for each source value// - Unlike switchMap, previous inner observables are NOT cancelled// - B's inner continues even after C arrives (B3 is still emitted)// - All inner observables run concurrently and their results are merged
const input$ = source<string>();
const result$ = input$.pipe( mergeMap((letter) => { const inner$ = source<string>();
setTimeout(() => { inner$.next(`${letter}1`); }, 10);
setTimeout(() => { inner$.next(`${letter}2`); }, 110);
setTimeout(() => { inner$.next(`${letter}3`); }, 210);
return inner$; }),);
const valueHistory: string[] = [];
result$.subscribe((value) => { valueHistory.push(value);});
const sleep = (ms: number): Promise<void> => new Promise((resolve) => { setTimeout(resolve, ms); });
// Emit A - inner emits A1, A2, A3 at 10ms, 110ms, 210msinput$.next('A');
await sleep(250);
assert.deepStrictEqual(valueHistory, ['A1', 'A2', 'A3']);
// Emit B - inner starts emitting B1, B2 at 10ms, 110msinput$.next('B');
await sleep(150);
assert.deepStrictEqual(valueHistory, ['A1', 'A2', 'A3', 'B1', 'B2']);
// Emit C while B's inner is still running (B3 at 210ms not yet fired)// Unlike switchMap, B's inner is NOT cancelledinput$.next('C');
await sleep(250);
// B3 appears between C1 and C2, showing the merge behaviorassert.deepStrictEqual(valueHistory, [ 'A1', 'A2', 'A3', 'B1', 'B2', 'C1', 'B3', 'C2', 'C3',]);