0
0
AngularHow-ToBeginner · 3 min read

How to Use concatMap in RxJS: Syntax and Examples

Use 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 observable
  • innerObservable: an observable created from the value
typescript
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);
Output
Processed 1 Processed 2 Processed 3
💻

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.

typescript
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);
Output
Number: 10 Number: 20 Number: 30
⚠️

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.

typescript
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);
Output
MergeMap 3 MergeMap 2 MergeMap 1 ConcatMap 1 ConcatMap 2 ConcatMap 3
📊

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.

FeatureDescription
PurposeMap and flatten observables sequentially
OrderPreserves order of emissions
Waits forEach inner observable to complete
Use caseSequential async operations
ReturnsObservable with all inner emissions concatenated

Key Takeaways

Use concatMap to handle observables sequentially, preserving order.
concatMap waits for each inner observable to complete before starting the next.
Always return an observable inside concatMap's mapping function.
Avoid mergeMap or switchMap if you need ordered processing.
concatMap is ideal for tasks like API calls that must run one after another.