How to Use concatMap in RxJS: Syntax and Examples
concatMap in RxJS to map each value from a source observable to an inner observable and subscribe to them one after another, preserving order. It waits for each inner observable to complete before moving to the next, making it ideal for sequential async tasks.Syntax
The concatMap operator takes a function that returns an observable for each value emitted by the source observable. It subscribes to each inner observable in order, waiting for one to complete before starting the next.
sourceObservable.pipe(concatMap(value => innerObservable))value: each item from the source observableinnerObservable: an observable created from the value
import { of } from 'rxjs'; import { concatMap, delay } from 'rxjs/operators'; const source$ = of(1, 2, 3); source$.pipe( concatMap(value => of(`Processed ${value}`).pipe(delay(1000))) ).subscribe(console.log);
Example
This example shows how concatMap processes each number from the source observable by mapping it to a delayed observable. Each output appears after the previous one completes, preserving order.
import { of } from 'rxjs'; import { concatMap, delay } from 'rxjs/operators'; const numbers$ = of(10, 20, 30); numbers$.pipe( concatMap(num => of(`Number: ${num}`).pipe(delay(500))) ).subscribe(console.log);
Common Pitfalls
One common mistake is using mergeMap or switchMap when order matters, which can cause outputs to appear out of sequence. Another is forgetting that concatMap waits for each inner observable to complete, which can slow down processing if inner observables take long.
Also, returning a non-observable inside concatMap will cause errors.
import { of } from 'rxjs'; import { mergeMap, concatMap, delay } from 'rxjs/operators'; const source$ = of(1, 2, 3); // Wrong: mergeMap may emit out of order source$.pipe( mergeMap(value => of(`MergeMap ${value}`).pipe(delay(1000 - value * 300))) ).subscribe(console.log); // Right: concatMap preserves order source$.pipe( concatMap(value => of(`ConcatMap ${value}`).pipe(delay(1000 - value * 300))) ).subscribe(console.log);
Quick Reference
concatMap is best when you need to:
- Process async tasks one by one
- Keep the order of results
- Wait for each inner observable to finish before starting the next
Use concatMap with a function returning an observable for each source value.
| Feature | Description |
|---|---|
| Purpose | Map and flatten observables sequentially |
| Order | Preserves order of emissions |
| Waits for | Each inner observable to complete |
| Use case | Sequential async operations |
| Returns | Observable with all inner emissions concatenated |