0
0
Angularframework~5 mins

mergeMap vs concatMap vs exhaustMap in Angular

Choose your learning style9 modes available
Introduction

These operators help manage multiple tasks that happen over time, like clicking buttons or loading data. They decide how to handle new tasks when old ones are still running.

When you want to start all tasks immediately and handle their results as they come (like loading multiple images at once).
When you want to run tasks one after another, waiting for each to finish before starting the next (like processing orders in sequence).
When you want to ignore new tasks if one is already running (like preventing double clicks on a submit button).
Syntax
Angular
sourceObservable.pipe(operator(projectFunction))

sourceObservable is the stream of events or data.

operator is one of mergeMap, concatMap, or exhaustMap.

Examples
Starts all HTTP calls immediately as values come in.
Angular
source$.pipe(mergeMap(value => httpCall(value)))
Waits for each HTTP call to finish before starting the next.
Angular
source$.pipe(concatMap(value => httpCall(value)))
Ignores new values if an HTTP call is already running.
Angular
source$.pipe(exhaustMap(value => httpCall(value)))
Sample Program

This Angular component listens for button clicks. Each click triggers a fake request that takes 1 second. Using mergeMap, all clicks start requests immediately, so results may overlap. Changing to concatMap makes requests run one after another. Using exhaustMap ignores clicks while a request is running.

Angular
import { Component } from '@angular/core';
import { fromEvent, of } from 'rxjs';
import { mergeMap, concatMap, exhaustMap, delay } from 'rxjs/operators';

@Component({
  selector: 'app-map-demo',
  template: `
    <button id="btn">Click me</button>
    <p>{{output}}</p>
  `
})
export class MapDemoComponent {
  output = '';

  ngOnInit() {
    const button = document.getElementById('btn');
    const clicks$ = fromEvent(button!, 'click');

    // Change operator here to mergeMap, concatMap, or exhaustMap
    clicks$.pipe(
      mergeMap(() => this.fakeRequest())
    ).subscribe(result => {
      this.output += result + '\n';
    });
  }

  fakeRequest() {
    // Simulates a request that takes 1 second
    return of('Request done').pipe(delay(1000));
  }
}
OutputSuccess
Important Notes

mergeMap is good for parallel tasks but can cause many overlapping results.

concatMap keeps order and waits, useful when sequence matters.

exhaustMap prevents overload by ignoring new tasks during an active one.

Summary

mergeMap: runs all tasks at once, results come as they finish.

concatMap: runs tasks one by one, preserving order.

exhaustMap: ignores new tasks if one is running, good for preventing duplicates.