This notebook provides a quick reference guide to RxJS operators and patterns that you'll commonly use in reactive programming. Whether you're building Angular applications, React with RxJS, or Node.js event-driven systems, this cheatsheet will help you find the right operator for your use case.
We'll cover creation operators, transformation techniques, filtering methods, error handling, multicasting with Subjects, and practical patterns - all with runnable examples.
$ npm install rxjs added 2 packages in 2s 28 packages are looking for funding run `npm fund` for details
RxJS loaded successfully
Creation operators create Observables from various sources.
of operator example: Fruit: apple Fruit: banana Fruit: cherry
from operator with array: Number: 1 Number: 2 Number: 3 from operator with promise: Promise resolved
fromEvent example (simulated): Event received: {"type":"click","x":100,"y":200} Event received: {"type":"click","x":120,"y":240}
map operator example: Doubled: 2 Doubled: 4 Doubled: 6 Doubled: 8 Doubled: 10
range operator example: Range emitted: 5 Range emitted: 6 Range emitted: 7 iif operator example: Condition is true (Random condition was true)
These operators transform emitted values.
map operator example: Doubled: 2 Doubled: 4 Doubled: 6 Doubled: 8 Doubled: 10
pluck operator example: Name: Alice Name: Bob Job Title: Developer Job Title: Designer
scan operator example: Click count: 1 Click count: 2 Click count: 3
switchMap example: Searching for: r Searching for: re Searching for: rea Searching for: reac Searching for: react Searching for: redux Results for "redux"
switchMap example: Searching for: r Searching for: re Searching for: rea Searching for: reac Searching for: react Searching for: redux Results for "redux"
exhaustMap example: Processing click click-1
Filtering operators examples: filter (even numbers): 2 4 6 8 10 take(3): 1 2 3 first(even): 2 last(): 10
These operators filter values from the stream.
Filtering operators examples: filter (even numbers): 2 4 6 8 10 take(3): 1 2 3 first(even): 2 last(): 10
Combination operators: merge operator: (interleaves both streams) A B C X Y Z concat operator: (stream1 then stream2) A B C X Y Z User typing with repeats: "aabbc" Throttled input: a Distinct input: a Distinct input: aa Distinct input: aab Throttled input: aabb Distinct input: aabb Distinct input: aabbc Debounced input: aabbc
These operators combine multiple Observables.
Combination operators: merge operator: (interleaves both streams) A B C X Y Z concat operator: (stream1 then stream2) A B C X Y Z
Combining latest values from streams: combineLatest example: zip example: Combined: red circle Zipped: red circle Combined: green circle Combined: green square Zipped: green square Combined: blue square
forkJoin for parallel API calls: Loading user profile data... User preferences loaded User data loaded User posts loaded All data loaded, ready to display profile: { "user": { "id": 1, "name": "John Doe" }, "posts": [ { "id": 1, "title": "Post 1" }, { "id": 2, "title": "Post 2" } ], "preferences": { "theme": "dark", "notificationsEnabled": true } }
These operators help with handling errors in reactive streams.
catchError example (success case): Received: API data catchError example (error case): Caught error: API request failed Received: Fallback data
retry and retryWhen examples: Simple retry (3 attempts): API attempt 1 API attempt 2 API attempt 3 API data successfully retrieved
Basic Subject example: Emitting values to subject: Subscriber 1 received: First value Subscriber 2 received: First value Subscriber 1 received: Second value Subscriber 2 received: Second value API attempt 3 Retrying after 800ms (attempt 3) API attempt 4 API data with backoff retry success
Subjects are both Observables and Observers, useful for multicasting.
Basic Subject example: Emitting values to subject: Subscriber 1 received: First value Subscriber 2 received: First value Subscriber 1 received: Second value Subscriber 2 received: Second value
BehaviorSubject example: First subscriber: Initial value First subscriber: Updated value Second subscriber: Updated value Current value: Updated value
ReplaySubject example: New subscriber will get last 2 values: Replayed: Second value Replayed: Third value Replayed: Fourth value
AsyncSubject example: Completing AsyncSubject... First subscriber: Final value - will be emitted Second subscriber: Final value - will be emitted Late subscriber: Final value - will be emitted
HTTP request caching pattern: First request to /api/data - should be a cache miss: ❓ Cache miss for /api/data 🌐 HTTP GET: /api/data With share() - only one execution: Shared Observable execution: 0 Shared Observer 1: 0 Shared Observer 2: 0 💾 Cached response for /api/data 📄 Response from /api/data Second request to /api/data after 1s - should be a cache hit: 🏎️ Cache hit for /api/data (age: 0ms) 📄 Response from /api/data Shared Observable execution: 1 Shared Observer 1: 1 Shared Observer 2: 1 Shared Observable execution: 2 Shared Observer 1: 2 Shared Observer 2: 2 Third request to /api/data after 3s - should be a cache miss (expired): ⏱️ Cache expired for /api/data (age: 2010ms) 🌐 HTTP GET: /api/data
Common patterns you'll use in reactive applications.
Typeahead search pattern: User typed: r Source Observable execution: 1 Observer 1: 1 Source Observable execution: 1 Observer 2: 1 User typed: re User typed: rea User typed: reac Source Observable execution: 2 Observer 1: 2 Source Observable execution: 2 Observer 2: 2 User typed: react 🔍 Searching API for: "react" 📋 Results for "react" Typeahead demo completed
HTTP request caching pattern: First request to /api/data - should be a cache miss: ❓ Cache miss for /api/data 🌐 HTTP GET: /api/data With share() - only one execution: Shared Observable execution: 0 Shared Observer 1: 0 Shared Observer 2: 0 💾 Cached response for /api/data 📄 Response from /api/data Second request to /api/data after 1s - should be a cache hit: 🏎️ Cache hit for /api/data (age: 0ms) 📄 Response from /api/data Shared Observable execution: 1 Shared Observer 1: 1 Shared Observer 2: 1 Shared Observable execution: 2 Shared Observer 1: 2 Shared Observer 2: 2 Third request to /api/data after 3s - should be a cache miss (expired): ⏱️ Cache expired for /api/data (age: 2010ms) 🌐 HTTP GET: /api/data 💾 Cached response for /api/data 📄 Response from /api/data
Rate limiting pattern: Creating rate limiter with max 2 concurrent operations: Submitting 6 items rapidly: ⚙️ Processing item 1... ⚙️ Processing item 2... ✅ Processed item 1 ⚙️ Processing item 3... ✅ Processed item 2 ⚙️ Processing item 4... ✅ Processed item 3 ⚙️ Processing item 5... ✅ Processed item 4 ⚙️ Processing item 6... ✅ Processed item 5 ✅ Processed item 6
Always unsubscribe from long-lived Observables to prevent memory leaks:
const subscription = observable.subscribe(...);
// Later when done
subscription.unsubscribe();
Use takeUntil for declarative unsubscription:
const destroy$ = new Subject();
observable.pipe(
takeUntil(destroy$)
).subscribe(...);
// When done
destroy$.next();
destroy$.complete();
Choose the right flattening operator:
switchMap
: Cancel previous and switch to new (search, latest value)mergeMap
: Process all in parallel (independent operations)concatMap
: Process in sequence (order matters)exhaustMap
: Ignore new until current completes (prevent duplicates)Avoid nested subscribes - use flattening operators instead:
// BAD
observable1.subscribe(value1 => {
observable2.subscribe(value2 => { /* ... */ });
});
// GOOD
observable1.pipe(
switchMap(value1 => observable2)
).subscribe(value2 => { /* ... */ });
Use share() or shareReplay() for multicasting:
const shared$ = observable.pipe(share());
const cached$ = observable.pipe(shareReplay({bufferSize: 1, refCount: true}));
Handle errors properly to prevent breaking your stream:
observable.pipe(
catchError(err => {
console.error('Error caught:', err);
return of(fallbackValue); // Return fallback Observable
})
)
Use finalize() for cleanup operations:
observable.pipe(
finalize(() => console.log('Done - cleaning up resources'))
)
Implement cancellation for long operations with takeUntil:
const cancel$ = new Subject();
longOperation$.pipe(
takeUntil(cancel$)
).subscribe(...);
// Call this to cancel
cancel$.next();
Use BehaviorSubject for state management:
const state$ = new BehaviorSubject(initialState);
// Update state
state$.next({...state$.getValue(), property: newValue});
// React to state changes
state$.subscribe(state => updateUI(state));
Prefer pipeable operators over prototype operators for better tree-shaking
RxJS provides powerful tools for handling asynchronous operations in a functional, reactive way. This cheatsheet covered:
RxJS has a learning curve, mastering these core operators and patterns will help you create more maintainable, declarative, and robust asynchronous code.