24 Jul 2024
2 min

concatMap – RxJS Reference

concatMap

concatMap operator is basically a combination of two operators – concat and map. The map part lets you map a value from a source observable to an observable stream. Those streams are often referred to as inner streams. The concat part works like concatAll – it combines all inner observable streams returned from the map and sequentially emits all values from every input stream.

As values from any combined sequence are produced, those values are emitted as part of the resulting sequence. Such process is often referred to as flattening in documentation.

Use this operator if the order of emissions is important and you want to first see values emitted by streams that come through the operator first.

The operator works in the following way:

  1. Subscribe to a source observable
  2. When a new value arrives from a source observable, execute a map function that returns an inner observable
  3. Subscribe to this inner observable
  4. When this inner observable emits a value, pass it down to an observer
  5. When a new value arrives from a source observable, execute a map function that returns an inner observable
  6. Put this inner observable in a queue
  7. Once the current inner observable completes, subscribe to the next inner observable in the queue
  8. Only after source observable completes and all inner observables complete, send the complete notification to the observer.
  9. If any of the inner observables throws an error, send the error notification to the observer.

Usage

This operator is mostly used when you need to map a plain value to an observable. A common use case is mapping URL strings into HTTP requests. As opposed to mergeMap, concatMap allows to execute all requests in a sequence – only once the previous request completes, a new request is initiated via subscription.

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

const urls = [
   'https://api.mocki.io/v1/0350b5d5',
   'https://api.mocki.io/v1/ce5f60e2'
];

from(urls).pipe(
   concatMap((url) => {
       return fromFetch(url);
   })
).subscribe((response) => console.log(response.status));

Playground

Additional resources

See also

Frequently asked questions

What is the difference between concatMap and mergeMap in RxJS?

concatMap processes inner observables sequentially: it subscribes to the next inner observable only after the current one completes, preserving emission order. mergeMap subscribes to every inner observable immediately, so their emissions can interleave. Use concatMap when order matters, such as executing HTTP requests one after another, and mergeMap when requests can run in parallel.

How do I make sequential HTTP requests in RxJS using concatMap?

Pass each value from a source observable to concatMap() and return an inner observable, such as fromFetch(url), from the mapping function. For example, from(urls).pipe(concatMap((url) => fromFetch(url))).subscribe(...) runs each request only after the previous one completes. Each response is then emitted in the order the requests were queued.

How does concatMap queue inner observables in RxJS?

When a new value arrives from the source, concatMap runs the mapping function and places the returned inner observable in a queue rather than subscribing immediately. Once the current inner observable completes, it subscribes to the next one in the queue. The complete notification is sent to the observer only after the source and all inner observables have completed.

What happens when an inner observable errors in concatMap?

If any inner observable in a concatMap() chain throws an error, the error notification is sent straight to the observer. Because inner observables run sequentially, later items in the queue are not processed after the error. Handle failures inside the inner observable, for example with catchError(), if the remaining sequence should continue.

When should I use concatAll instead of concatMap in RxJS?

Use concatAll() when you already have a higher-order observable that emits inner observables and only need to flatten them in order. Use concatMap() when you start from plain values and need to map each one to an inner observable in a single step. concatMap is essentially map combined with concatAll.

Share this post

Sign up for our newsletter

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