24 Jul 2024
5 min

exhaustMap – RxJS Reference

exhaustMap

exhaustMap operator is basically a combination of two operators – exhaust and map. The map part lets you map a value from a higher-order source observable to an inner observable stream. The exhaust part than subscribes to an inner observable and passes values down to an observer if there’s no active subscription already, otherwise it just ignores new inner observables.

exhaustMap has only one active subscription at a time from which the values are passed down to an observer. When the higher-order observable emits a new inner observable stream, if the current stream hasn’t completed, this new inner observable is dropped. Once the current active stream completes, the operator waits for another inner observable to subscribe ignoring previous inner observables.

The operator works in the following way:

  1. Subscribe to a higher-order source observable
  2. When a new inner observable arrives from a source observable, check if there’s no active subscription
  3. If there’s an active subscription, ignore the observable
  4. If there’s no active subscription, execute a map function that returns an inner observable and subscribe to it
  5. When a new value arrives from this inner observable, pass it down to an observer
  6. Only after a higher-order source observable and current active subscriptions complete, send the complete notification to the observer.
  7. If any of the inner source observables throws an error, send the error notification to the observer.

Please note that exhaustMap will never complete if some input streams don't complete. This also means that some streams will never be subscribed to.

Usage

exhaustMap is useful when your system can produce multiple actions that trigger a long lasting task, like a login HTTP request, and all other similar actions should be ignored until the current task is complete.

Here’s an example of using exhaustMap to do exactly this:

const request = (index) => timer(500).pipe(take(1), mapTo({index}));

const a = request(1);
const b = request(2);
const actions = interval(100).pipe(take(2), map((v, i) => [a, b][i]));

// logs 1
actions.pipe(exhaustMap((request) => request)).subscribe((res: any) => console.log(res.index));

Playground

Additional resources

See also

Share this post

Sign up for our newsletter

Stay up-to-date with the trends and be a part of a thriving community.