RxJS operators
RxJS operators are functions that enable you to manipulate, combine, filter, and transform the data streams (Observables) in powerful ways. They take an Observable as input and return a new Observable.
Think of operators as tools in a workshop for working with your asynchronous data streams. Instead of listing every single operator (there are many!), it's helpful to understand the general categories they fall into, based on what they do:
Creation Operators#
- Purpose: To create new Observables from scratch or from existing data sources.
-
Examples:
of
: Creates an Observable that emits the provided values sequentially and then completes.from
: Converts arrays, promises, iterables, or strings into Observables.fromEvent
: Creates an Observable from DOM events. (Hot Observable)interval
: Emits sequential numbers every specified interval (in milliseconds).timer
: Emits one value after an initial delay, then optionally emits subsequent values at a regular interval.throwError(() => new Error('Oops!'))
: Creates an Observable that immediately emits an error.EMPTY
: Creates an Observable that emits no items and immediately completes.NEVER
: Creates an Observable that never emits any items and never completes.
Transformation Operators#
- Purpose: To change the format, type, or value of items emitted by an Observable.
-
Examples:
map
: Applies a function to each emitted value.pluck('propertyName')
: Selects a nested property from each emitted object.scan((acc, value) => acc + value, 0)
: Accumulates values over time, likeArray.reduce
.mergeMap
: Projects each source value to an Observable and merges their emissions into a single stream. Good for handling multiple inner observables concurrently.switchMap
: Projects each source value to an Observable, but cancels the previous inner Observable when a new source value arrives. Ideal for scenarios like type-ahead searches where you only care about the latest request.concatMap
: Projects each source value to an Observable, but waits for the previous inner Observable to complete before subscribing to the next one. Ensures order.bufferTime(1000)
: Collects emitted values into arrays over a specified time period.groupBy(item => item.category)
: Groups items emitted by the source Observable based on a key.
Filtering Operators#
- Purpose: To selectively emit values from a source Observable based on certain criteria.
-
Examples:
filter
: Emits only the values that satisfy a condition.first
: Emits only the first value (or the first value satisfying a condition) and then completes.last
: Emits only the last value (or the last value satisfying a condition) when the source completes.take
: Emits the first N values and then completes.takeUntil
: Emits values until a secondnotifier$
Observable emits. Very useful for unsubscribing/completing streams (e.g., when a component is destroyed).skip
: Skips the first N values.debounceTime
: Emits a value only after a specified time has passed without another source emission. Useful for rate-limiting input events (like search inputs).distinctUntilChanged
: Emits only when the current value is different from the previous one.
Combination Operators#
- Purpose: To combine multiple source Observables into a single Observable.
-
Examples:
combineLatest
: When any source Observable emits, it combines the latest values from all sources and emits the combined result (usually as an array). Requires all sources to have emitted at least once.zip
: Combines values from source Observables pairwise. Waits for each source to emit a value at the corresponding index before emitting the combined pair.forkJoin
: Waits for all source Observables to complete and then emits an array containing the last value emitted by each source. Good for running parallel asynchronous operations and getting all results at the end.merge(obs1$, obs2$)
: Subscribes to all source Observables and simply passes through any value emitted by any of them as soon as it arrives. Order depends on timing.concat(obs1$, obs2$)
: Subscribes to the first Observable, emits all its values, and only then subscribes to the second Observable, emits its values, and so on. Preserves order strictly.race(obs1$, obs2$)
: Mirrors the first Observable (eitherobs1$
orobs2$
) to emit a value. Ignores the other(s).
Error Handling Operators#
- Purpose: To gracefully handle errors that might occur in an Observable sequence.
-
Examples:
catchError
: Catches errors from the source Observable and either returns a replacement Observable (e.g., emitting a default value) or re-throws the error (or a new one).retry
: Re-subscribes to the source Observable up to N times if it encounters an error.retryWhen
: Re-subscribes based on logic defined in a notifier Observable (e.g., retry after a delay).
Utility Operators#
- Purpose: Miscellaneous operators useful for debugging, controlling timing, or other side effects.
-
Examples:
tap
: Perform side effects (like logging) for each emission without modifying the stream itself. (Formerly known asdo
).delay
: Delays the emission of each item by a specified time.timeout
: Emits an error if the source Observable doesn't emit a value within a specified time.finalize
: Executes a callback function when the source Observable completes or errors. Good for cleanup logic.toArray()
: Collects all source emissions into a single array and emits that array when the source completes.
Multicasting Operators#
- Purpose: To share a single subscription to an underlying Observable among multiple subscribers. This is key for turning Cold Observables Hot or optimizing shared resources.
-
Examples:
share
: Shares a single subscription but doesn't necessarily replay past values. Subscription starts with the first subscriber and stops when the last one unsubscribes.shareReplay
: Shares a single subscription and replays the lastbufferSize
emissions to new subscribers. Often used withbufferSize: 1
to share API calls. The underlying subscription might stay active even after subscribers leave, depending on configuration.publish()
,multicast()
: Lower-level operators for more complex multicasting scenarios, often used with Subjects.
Conditional and Boolean Operators#
- Purpose: To evaluate conditions across sequences or emit boolean values.
-
Examples:
every(x => x > 0)
: Emitstrue
if all values satisfy the predicate,false
otherwise, then completes.find(x => x === 5)
: Emits the first value that satisfies the predicate, then completes.isEmpty()
: Emitstrue
if the source completes without emitting any values,false
otherwise.defaultIfEmpty('default')
: Emits a default value if the source completes without emitting anything.
Understanding these categories helps you navigate the RxJS library and choose the right tool for transforming, filtering, combining, or managing your asynchronous data streams effectively in Angular applications.