RxJs ships with a vast catalog of operators, yet most real-world applications tend to rely on a surprisingly small subset of them.
After the array-like operators such as map and filter, one of the first non-array operators developers encounter—and quickly come to depend on—is switchMap.
Rather than diving straight into theory, let's observe how the operator behaves in practice across two distinct stream categories:
- short-lived streams like HTTP requests, which produce exactly one value and then terminate
- long-lived streams such as those supplied by AngularFire, an Angular library for Firebase's real-time database and authentication services
We will conclude by examining a frequent, but less obvious, application: merging the emissions of several Observables into a single output.
Suggested Reading
For an exhaustive comparison of the switchMap, mergeMap, concatMap, and exhaustMap operators, refer to:
Recreating HTTP and Firebase Observable Patterns
To isolate the core mechanics of the operator, we'll define a few helper functions that mimic the stream patterns commonly found in applications.
- Cold, single-emission, short-lived streams, analogous to Angular's HTTP layer
- Cold, multi-emission, long-lived streams, akin to AngularFire's data feeds
Understanding these foundational stream types is a prerequisite for mastering switchMap, so let's examine them closely.
The Lifecycle of Angular HTTP Observables
Let's begin by emulating the Observables returned by Angular's HTTP client, often the first streams a beginner encounters.
These Observables are distinguished by a few specific characteristics that are not universal:
- they are cold (deferred), meaning no values are produced until a subscriber is attached
- they emit either a single value or an error, followed by a completion signal, so they are short-lived
- explicit unsubscription is unnecessary in most cases because the stream completes on its own
Building a Mock HTTP Request Stream
Given these traits, here is a factory function that produces Observables with identical behavior:
Within it, the of utility is employed to create an "emit once and done" stream, and the delay operator is piped in to simulate network latency.
Let's verify this function by creating two Observables that mimic separate HTTP calls:
Both Observables are cold, so they stay inert until subscribed. We'll subscribe to each and observe the console output:
A Compact Logging Pattern for Testing
Note the concise subscription syntax used here. The http1$ subscription is functionally identical to:
This shorthand works by passing console.log and console.error directly as callbacks, instead of writing anonymous arrow functions. It's a handy trick for quick debugging. Let's see the output:
1
http1$ completed
2
http2$ completed
The result is typical of Angular HTTP Observables: a single value (or possibly an error) is emitted, and then the stream completes immediately.
First Look at Switch Map
Now, let's put switchMap to work by chaining two dependent HTTP requests.
The scenario: we need to save a user's data on the server, and then fetch a secondary dataset affected by that save.
The simulation might look like this:
Let's walk through the program's output:
simulating HTTP requests
user saved
data reloaded
completed httpResult$
From this example, we can extract the fundamental mechanics of switchMap in action:
- The
saveUser$Observable acts as the source - The stream resulting from
switchMapis theresultObservable$ - without a subscriber, the
resultObservable$remains dormant - subscribing to it creates a subscription to the
saveUser$source - when the source emits, the value flows into the function provided to
switchMap - that function must return an Observable, which may or may not use the source value
- this returned Observable is the inner Observable
- the inner Observable is subscribed to, and each of its emissions is also emitted by the result observable
- the result observable completes only when the source completes
This pattern is ideal for orchestrating a second request based on the primary request's result—a common workflow. However, this simple example leaves questions unanswered, particularly regarding the operator's naming.
Deconstructing the SwitchMap Name
A name often clarifies a concept. Let's scrutinize the two parts of this operator's name:
- what exactly is being
switched, and from what to what? - what is being
mapped in this context?
One might assume the "switch" occurs from the source Observable to the inner Observable. As we'll see, that's not the case.
The "map" part is often easier to intuit; it refers to the act of mapping the emitted source value into a brand new Observable.
Let's now identify the true target of the "switch".
The Need for Longer-lived Streams
The HTTP-like streams we've explored so far, while useful, make it hard to appreciate the full power of switchMap. Since they emit once and complete, the operator's dynamic nature is obscured. To truly observe it in action, we need streams that emit multiple times—the AngularFire-like variety.
Simulating AngularFire's Data Streams
We'll create a new utility function to generate these long-lived Observables:
Let's use it to create two Observables that mimic Firebase's real-time data feeds:
Characteristics of the Firebase-like Streams
What sets these streams apart? Let's analyze the output of our simulation above:
1: FB-2 0
2: FB-2 1
3: FB-2 2
4: FB-2 3
5: FB-1 0
6: FB-2 4
7: FB-2 5
8: FB-2 6
9: FB-2 7
10: FB-2 8
11: FB-1 1
12: FB-2 9
...
Long-lived vs. Short-lived
The behavior is distinctly different from the HTTP streams we've seen. Let's break it down, starting from the bottom up:
- the immediate and obvious difference is that these streams don't complete; they persist and keep emitting values
- the stream will continue pushing new values indefinitely until an unsubscribe action is taken
firebase2$has a 1-second interval, thus a higher emission frequency- the
firebase1$stream, with a 5-second interval, produces fewer values in the same timeframe.
The Inner Workings of SwitchMap, Revealed
With these long-lived streams, we can now observe what switchMap truly does. Let's chain these two streams together and predict the output:
We'll wire them up like this—with some indentation added to the output for clarity:
source value FB-1 0
inner observable 0
inner observable 1
inner observable 2
inner observable 3
source value FB-1 1
inner observable 0
inner observable 1
inner observable 2
inner observable 3
source value FB-1 2
inner observable 0
inner observable 1
inner observable 2
...
The Origin of the "Switch"
Let's dissect this output to see why switch is part of the name:
- as before, no output is generated until the result observable is subscribed to
- the source stream emits its first value,
FB-1 0 - this value is mapped to an inner observable using our function
- the inner observable is then subscribed to
- the result observable dutifully reflects the emissions of the inner stream
- notice the inner stream starts at 0, emitting values from a newly created interval
The Meaning of Switch in this Context
Here's where things diverge from the HTTP example. Since the source stream is long-lived, it eventually emits a second value, FB-1 1.
The moment this new value arrives, the behavior changes dramatically:
- the previously active inner observable, which was about to emit index 3, is silently abandoned
- our mapping function is invoked again, generating a fresh, brand new inner observable
- this new inner observable is subscribed to
- the new inner observable begins its emission sequence from index 0
- the result observable now emits values from this new inner observable, having forgotten the old one
But What Actually Happened to the Old Stream?
The original inner observable wasn't paused. It was unsubscribed from, discarding its future values.
The result observable performed a
switch. Its allegiance moved from the original inner observable to the newly minted one.
This single `switch` operation defines the very essence of the switchMap name.
SwitchMap, Condensed
To summarize: switchMap listens to a source Observable. For each value it receives, it creates a new inner Observable. It subscribes to this new inner Observable and emits its values downstream.
A source emission triggers a cancellation: the previous inner Observable is unsubscribed, and the focus shifts entirely to the new one. It is crucial to understand that the source Observable itself is never cancelled, only those transient inner Observables.
That's the whole story—the name, the mechanism, and the primary use case. But there is a lesser-known benefit that makes this operator even more valuable.
Combining Emissions from Multiple Observables
Imagine you need the final value to include data from both the source and the inner Observable. This isn't about replacing one with another.
Instead, you can merge them into a single output. A simple way is to use the map operator inside switchMap's function to combine the values into a single structure, like a tuple:
Observing the Combined Output
Let's examine the console. The result observable is no longer emitting a single value. Instead, it emits a combination:
[Object, Array(30)]
The final output objects are plain JavaScript arrays. Inside, we see:
- the first entry is a course object, coming from the initial HTTP request (the source)
- the second entry is an array of lessons, which originates from the inner Observable
Wrapping Up
The switchMap operator is a cornerstone of many RxJs applications. A solid grasp of its mechanics will help you implement complex, asynchronous workflows with confidence.
You will likely find yourself using it in nearly every project you build.
I hope this exploration clarifies how it operates. To stay informed when further articles on popular RxJs operators are released, consider subscribing to our newsletter:
For a deeper dive into RxJs, we recommend our RxJs In Practice Course. It provides numerous practical patterns and detailed explanations of many operators.
If you are new to Angular itself, you might find the Angular for Beginners Course to be a helpful starting point:
Further Reading on Angular
Here are other posts you may find useful:
- Getting Started With Angular - Development Environment Best Practices With Yarn, the Angular CLI, Setup an IDE
- Why a Single Page Application, What are the Benefits ? What is a SPA ?
- Angular Smart Components vs Presentation Components: What's the Difference, When to Use Each and Why?
- Angular Router - How To Build a Navigation Menu with Bootstrap 4 and Nested Routes
- Angular Router - Extended Guided Tour, Avoid Common Pitfalls
- Angular Components - The Fundamentals
- How to build Angular apps using Observable Data Services - Pitfalls to avoid
- Introduction to Angular Forms - Template Driven vs Model Driven
- Angular ngFor - Learn all Features including trackBy, why is it not only for Arrays ?
- Angular Universal In Practice - How to build SEO Friendly Single Page Apps with Angular
- How does Angular Change Detection Really Work ?
