RXJS
1. What is RxJS, and how is it used in Angular?
RxJS (Reactive Extensions for JavaScript) is a library for reactive programming
using Observables. It is extensively used in Angular for handling asynchronous
data streams and events, such as HTTP requests, user interactions, or WebSocket
messages. RxJS allows developers to work with asynchronous data using operators
like map, filter, switchMap, mergeMap, etc. Angular leverages RxJS in
components, services, and other parts of the application, especially for
handling HTTP requests and reactive forms.
2. What are Observables in RxJS and how do they work in
Angular?
An Observable is a core concept in RxJS. It represents a collection of future
values or events. In Angular, an Observable is typically used to handle
asynchronous operations like HTTP requests. Components subscribe to an
Observable to get the values emitted by it. When an Observable emits a value,
all subscribers are notified. Angular services return Observables for tasks
like fetching data from APIs, and components subscribe to these Observables to
display or use the data.
Example:
this.httpClient.get('/api/data').subscribe(data => {
console.log(data);
});
3. What is the purpose of the async pipe in Angular?
The async pipe in Angular is used to automatically subscribe to an Observable
or a Promise and return the latest emitted value. It also handles the
unsubscription when the component is destroyed. This pipe is often used in
templates to simplify working with Observables, eliminating the need to
manually subscribe and unsubscribe.
Example:
<div *ngIf="data$ | async as data">
{{ data.name }}
</div>
4. Explain the difference between switchMap and mergeMap
in RxJS.
- switchMap:
This operator is used when you want to cancel the previous inner
Observable whenever a new value is emitted. It switches to the latest
Observable and unsubscribes from the previous one. It is particularly
useful for scenarios like autocomplete or live search.
- mergeMap:
This operator is used when you want to merge multiple Observables into one
without cancelling any previous ones. It subscribes to all inner
Observables concurrently and emits all their values.
Example:
// Using switchMap
this.searchTerm$.pipe(
switchMap(term =>
this.searchService.search(term))
);
// Using mergeMap
this.searchTerm$.pipe(
mergeMap(term =>
this.searchService.search(term))
);
5. What is the difference between take(1) and first()
operators in RxJS?
- take(1):
This operator allows you to take the first value emitted by the Observable
and then automatically unsubscribe. It’s useful when you want to grab a
single value without worrying about future emissions.
- first():
Similar to take(1), but it also accepts a predicate to specify a condition
for the first value emitted. If no predicate is provided, it behaves like
take(1).
Example:
// take(1) example
this.httpClient.get('/api/data').pipe(take(1)).subscribe(data
=> console.log(data));
// first() with predicate
this.httpClient.get('/api/data').pipe(first(data =>
data.status === 'active')).subscribe(data => console.log(data));
6. How can you prevent memory leaks when working with
RxJS in Angular?
Memory leaks in Angular can occur if Observables are not unsubscribed properly.
Common strategies to avoid memory leaks:
- Use
the async pipe in templates, which handles unsubscription automatically.
- Manually
unsubscribe from Observables in the ngOnDestroy lifecycle hook.
- Use
operators like takeUntil to manage unsubscription based on another
Observable (often a subject).
Example with takeUntil:
import { Subject } from 'rxjs';
export class MyComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() {
this.myObservable$
.pipe(takeUntil(this.destroy$))
.subscribe(data =>
console.log(data));
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
7. What does the debounceTime operator do in RxJS, and
when should it be used?
The debounceTime operator is used to wait for a specified time period after the
last emitted value before emitting the most recent one. It is commonly used to
handle scenarios like user typing in a search input, where you want to wait for
the user to stop typing before making an API call. It helps reduce the number
of unnecessary API calls.
Example:
this.searchTerm$
.pipe(debounceTime(300), switchMap(term =>
this.searchService.search(term)))
.subscribe(results => console.log(results));
8. How do you handle errors in RxJS Observables in
Angular?
You can handle errors in RxJS Observables using the catchError operator or the
subscribe error callback. The catchError operator allows you to catch errors
and handle them gracefully, such as by returning a fallback value or retrying
the request.
Example using catchError:
this.httpClient.get('/api/data').pipe(
catchError(error => {
console.error('Error occurred:',
error);
return of([]); // Return fallback
value
})
).subscribe(data => console.log(data));
9. What is the ReplaySubject in RxJS, and how is it used?
A ReplaySubject is a type of Subject that remembers the previous emitted values
and replays them to new subscribers. It can be useful when you want new
subscribers to receive the most recent value or a set of recent values. You can
specify how many values the ReplaySubject should replay by providing a buffer
size.
Example:
const replaySubject = new ReplaySubject(2); // Replay last 2
values
replaySubject.next(1);
replaySubject.next(2);
replaySubject.next(3);
replaySubject.subscribe(value => console.log(value)); //
Will receive 2 and 3
10. Explain the concept of "cold" and
"hot" Observables.
- Cold
Observables: These are Observables that do not begin emitting values
until they are subscribed to. Each subscription will get its own
independent execution of the Observable.
- Hot
Observables: These are Observables that emit values regardless of
subscriptions. Multiple subscribers will share the same execution of the
Observable and receive the same emitted values.
Example:
- HTTP
requests are typically cold Observables, meaning each subscriber triggers
a separate HTTP request.
- A
Subject is a hot Observable, as it will emit values to all subscribers
immediately when they subscribe.
11. What is concatMap in RxJS and when would you use it?
The concatMap operator is used to map each emitted value to an inner Observable
and concatenate the emissions from those inner Observables in a sequential
order. Unlike mergeMap, concatMap ensures that each inner Observable completes
before moving to the next one, so the order of emissions is preserved.
Use case: You would use concatMap when the order of
the emissions matters and you need to wait for one task to complete before
starting the next. For example, submitting form data sequentially.
Example:
this.formData$
.pipe(concatMap(data =>
this.submitForm(data)))
.subscribe(response =>
console.log(response));
12. What is the purpose of the shareReplay operator in
RxJS?
The shareReplay operator is used to multicast an Observable to multiple
subscribers, and it also replays a specified number of values to new
subscribers. This is useful when you want to share an Observable among multiple
consumers and avoid re-executing the underlying operation, such as a network
request, for every new subscriber.
Use case: Avoiding duplicate HTTP requests when
multiple components subscribe to the same Observable.
Example:
const sharedData$ =
this.httpClient.get('/api/data').pipe(shareReplay(1));
sharedData$.subscribe(data => console.log('Subscriber
1:', data));
sharedData$.subscribe(data => console.log('Subscriber
2:', data));
13. What is switchMap and how does it differ from
mergeMap?
- switchMap:
When a new value is emitted from the source Observable, switchMap cancels
the previous inner Observable and switches to the new one. This is useful
for scenarios where you need to cancel ongoing operations (e.g., switching
between search terms in an input box).
- mergeMap:
Unlike switchMap, mergeMap does not cancel the previous inner Observable.
It will merge the emissions from all inner Observables, allowing them to
execute concurrently. This is useful when you need to handle multiple
concurrent tasks and collect results from all of them.
Example of switchMap:
this.searchTerm$.pipe(
switchMap(term =>
this.searchService.search(term))
).subscribe(results => console.log(results));
Example of mergeMap:
this.searchTerm$.pipe(
mergeMap(term =>
this.searchService.search(term))
).subscribe(results => console.log(results));
14. What does takeUntil do, and how can it be useful in
Angular?
The takeUntil operator is used to automatically unsubscribe from an Observable
when another Observable emits a value. This is particularly useful for managing
subscriptions in Angular components, ensuring they are properly cleaned up when
a component is destroyed or when certain conditions are met.
Use case: Preventing memory leaks by ensuring
subscriptions are unsubscribed when the component is destroyed.
Example:
import { Subject } from 'rxjs';
export class MyComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() {
this.httpClient.get('/api/data').pipe(
takeUntil(this.destroy$)
).subscribe(data =>
console.log(data));
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
15. What is the difference between tap and map in RxJS?
- tap:
The tap operator is used for side effects. It does not alter the data
passing through it. It allows you to perform actions like logging,
debugging, or calling functions, but it does not change the emitted
values.
- map:
The map operator transforms the emitted values. It takes the input value,
processes it, and outputs a new value. The primary purpose of map is to
modify the data flow, not just to perform side effects.
Example:
// Using `map` to transform data
this.httpClient.get('/api/data').pipe(
map(data => data.items)
).subscribe(items => console.log(items));
// Using `tap` to log data without modifying it
this.httpClient.get('/api/data').pipe(
tap(data => console.log('Received data:',
data))
).subscribe();
16. What is the purpose of the auditTime operator in
RxJS?
The auditTime operator is used to emit the latest value from the source
Observable only after a specified amount of time has passed. It will ignore any
values emitted during that time window and will only emit the most recent value
once the time period is over.
Use case: This is useful for scenarios like limiting
the frequency of user input handling, such as implementing efficient scroll or
resize event listeners.
Example:
this.scrollEvent$.pipe(
auditTime(300)
).subscribe(() => {
console.log('Scrolled after 300ms');
});
17. What is the debounce operator in RxJS, and how does
it differ from debounceTime?
The debounce operator is similar to debounceTime, but it works based on the
value of the emitted item rather than a fixed time. It allows you to wait for
the source Observable to stop emitting values for a specific amount of time
before emitting the most recent one. This is often used when you need to
debounce user input, like a search bar, but with a condition based on the
emitted value.
Use case: Debouncing user inputs that require
specific conditions, like waiting for a value change to meet a certain
criterion.
Example:
this.searchTerm$.pipe(
debounce(() =>
this.myCustomDebounceCondition())
).subscribe(result => {
console.log(result);
});
18. How can you use combineLatest in Angular?
The combineLatest operator combines the latest values from multiple Observables
and emits the latest value from each source Observable as an array or object
when any of the Observables emits a new value.
Use case: Useful when you need to combine data from
multiple Observables (e.g., form fields, user profile data, etc.).
Example:
import { combineLatest } from 'rxjs';
combineLatest([this.username$,
this.password$]).subscribe(([username, password]) => {
console.log('Username:', username);
console.log('Password:', password);
});
19. What is the interval function in RxJS, and how can
you use it in Angular?
The interval function creates an Observable that emits increasing integer
values at regular intervals (in milliseconds). This can be useful for periodic
tasks or polling.
Use case: Polling a server or running an animation at
a fixed interval.
Example:
import { interval } from 'rxjs';
const timer$ = interval(1000); // Emits every second
timer$.subscribe(val => {
console.log('Tick:', val);
});
20. How would you implement retry logic with RxJS in
Angular?
You can use the retry or retryWhen operators in RxJS to automatically retry a
failed Observable operation. retry allows you to specify a number of retries,
while retryWhen gives you more control over the retry logic, including delays
between retries.
Use case: Retrying an HTTP request when it fails
temporarily.
Example with retry:
this.httpClient.get('/api/data').pipe(
retry(3) // Retry up to 3 times
).subscribe(data => console.log(data), error =>
console.error(error));
Example with retryWhen (using delay):
import { of } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
this.httpClient.get('/api/data').pipe(
retryWhen(errors => errors.pipe(
delay(1000), // Wait 1
second between retries
take(3) //
Retry up to 3 times
))
).subscribe(data => console.log(data), error =>
console.error(error));
21. What is share in RxJS, and how does it work in
Angular?
The share operator is used to share a single subscription to an Observable
among multiple subscribers. It works by multicast the source Observable, so
that it does not execute multiple times (like making multiple HTTP requests).
It’s a combination of publish and refCount that automatically subscribes and
unsubscribes based on the number of active subscribers.
Use case: Avoiding redundant HTTP requests or
expensive operations when multiple components need the same data.
Example:
const sharedData$ =
this.httpClient.get('/api/data').pipe(share());
sharedData$.subscribe(data => console.log('Subscriber
1:', data));
sharedData$.subscribe(data => console.log('Subscriber
2:', data));
22. What is concatAll in RxJS and when should you use it?
The concatAll operator is used to flatten an Observable of Observables by
subscribing to each inner Observable sequentially. It ensures that the outer
Observable will emit values from one inner Observable at a time, and only move
to the next inner Observable after the current one completes.
Use case: Useful when you need to execute
asynchronous tasks in sequence, where one task must complete before the next
starts.
Example:
this.outerObservable.pipe(concatAll()).subscribe(result
=> {
console.log(result); // The inner Observables
will be processed one at a time.
});
23. What is exhaustMap in RxJS, and when is it useful?
The exhaustMap operator is used to map to an inner Observable but ignores all
incoming emissions from the source Observable until the current inner
Observable completes. This ensures that only one inner Observable is active at
any time and ignores any new emissions during that time.
Use case: Useful in scenarios where you don't want to
start a new operation while an ongoing one is still running, such as form
submission where you don’t want to trigger multiple requests in parallel.
Example:
this.submitForm$
.pipe(exhaustMap(formData =>
this.formService.submit(formData)))
.subscribe(response =>
console.log(response));
24. What is takeWhile in RxJS and how does it work?
The takeWhile operator allows you to emit values from an Observable until a
specified condition is no longer true. Once the condition becomes false, it
completes the Observable. Unlike take, which limits the number of values,
takeWhile is based on a condition.
Use case: Stop processing values once a certain
condition is met, for example, when you reach the end of a list or stop a
timer.
Example:
this.timer$.pipe(takeWhile(val => val <
10)).subscribe(val => {
console.log(val); // Stops emitting values once
`val` is greater than or equal to 10.
});
25. How does window operator work in RxJS?
The window operator is used to group emitted values from the source Observable
into windows (Observables), which are emitted as separate Observables. These
windows can be controlled using another Observable, and each window emits
values until it is closed, then a new window is started.
Use case: It’s helpful when you want to break the
stream of values into smaller chunks, such as when handling events in batches.
Example:
import { interval } from 'rxjs';
import { window, take, mergeAll } from 'rxjs/operators';
interval(1000).pipe(
window(interval(3000)), // Group values emitted
every 3 seconds
take(2), // Take two windows
mergeAll() // Merge the windowed Observables
into one
).subscribe(value => console.log(value));
26. What is merge in RxJS and how is it different from
concat?
- merge:
Combines multiple Observables into a single Observable, emitting values
from all Observables concurrently, without waiting for each Observable to
complete first. This means that multiple inner Observables may emit values
simultaneously.
- concat:
Combines multiple Observables, but ensures that each Observable completes
before the next one is subscribed to. This ensures that the order of
emissions is strictly maintained.
Use case:
- Use
merge when you want to handle concurrent requests or parallel streams.
- Use
concat when you need to process tasks sequentially.
Example using merge:
import { merge } from 'rxjs';
merge(observable1, observable2).subscribe(data =>
console.log(data));
Example using concat:
import { concat } from 'rxjs';
concat(observable1, observable2).subscribe(data =>
console.log(data));
27. What does distinctUntilChanged do in RxJS?
The distinctUntilChanged operator ensures that only distinct values are emitted
based on consecutive emissions from the source Observable. It compares the
current value to the previous value, and only emits the new value if it is
different.
Use case: It is used to filter out consecutive
duplicate values, such as when observing a value that only changes when there’s
a meaningful change (e.g., form data input or button click).
Example:
this.inputValue$.pipe(
distinctUntilChanged()
).subscribe(value => console.log(value)); // Emits only
when the value is different from the previous one
28. What is the delay operator in RxJS and when is it
useful?
The delay operator is used to delay the emissions of an Observable by a
specified amount of time. It’s useful when you want to simulate a delay or
pause before emitting values.
Use case: You can use delay to simulate network
latency in tests, or to create UI delays like showing loading indicators.
Example:
this.httpClient.get('/api/data').pipe(
delay(2000) // Delay the emission by
2 seconds
).subscribe(data => console.log(data));
29. How does zip operator work in RxJS?
The zip operator combines multiple Observables into a single Observable by
emitting a combined value when each of the source Observables emits a value.
The combined value is emitted as an array (or tuple) of corresponding values
from each of the source Observables, and it only emits when all Observables
have emitted a value.
Use case: Used when you need to combine data from
multiple sources, but you want to process the values only when each Observable
has emitted an item.
Example:
import { zip } from 'rxjs';
const observable1 = of(1, 2, 3);
const observable2 = of('A', 'B', 'C');
zip(observable1, observable2).subscribe(([num, char]) =>
{
console.log(num, char); // Output will be: 1 A,
2 B, 3 C
});
30. What is the finalize operator in RxJS and how is it
used in Angular?
The finalize operator allows you to perform a side-effect action (like cleanup)
when an Observable completes or errors out. It’s useful when you need to
trigger actions such as stopping a loading indicator or cleaning up resources,
regardless of whether the Observable succeeds or fails.
Use case: It is often used to hide a loading spinner
or dismiss any ongoing UI actions once the Observable completes.
Example:
this.httpClient.get('/api/data').pipe(
finalize(() => {
this.isLoading = false; // Hide
loading spinner
})
).subscribe(data => {
console.log(data);
});
31. What is buffer in RxJS, and when would you use it?
The buffer operator collects values from the source Observable into an array
until another Observable emits a value. Once the other Observable emits, the
accumulated values are emitted as an array, and the collection process starts
over.
Use case: Useful when you need to group emissions
into arrays (or "batches") based on some external trigger, such as
collecting events until a user stops typing or some timeout.
Example:
import { buffer, interval, take } from 'rxjs';
interval(1000).pipe(
take(5), // Emit 5 values from the source
Observable
buffer(interval(3000)) // Collect values until
the next 3-second interval
).subscribe(values => {
console.log('Buffered Values:', values); // Emit
buffered values every 3 seconds
});
32. What does startWith do in RxJS?
The startWith operator is used to emit a specified value before any other
emissions from the source Observable. This allows you to provide an initial
value when subscribing to the Observable.
Use case: Use startWith to initialize a value, such
as displaying a default value before an API call completes or before any user
interaction.
Example:
this.data$.pipe(
startWith('Loading...')
).subscribe(value => console.log(value)); // Emits
'Loading...' before the actual data
33. What is catchError in RxJS, and how can it be used in
Angular?
The catchError operator is used to handle errors that occur in an Observable.
It allows you to catch errors and either return a fallback Observable or
rethrow the error to be handled downstream.
Use case: Use catchError when dealing with HTTP
requests or any other Observables where errors need to be handled gracefully,
such as showing an error message or retrying the operation.
Example:
import { catchError } from 'rxjs/operators';
this.httpClient.get('/api/data').pipe(
catchError(error => {
console.error('Error occurred:',
error);
return of([]); // Return a fallback
value (empty array)
})
).subscribe(data => console.log(data));
34. What is pairwise in RxJS?
The pairwise operator emits the previous and current values from the source
Observable as an array. It is useful when you need to track the change between
consecutive emissions.
Use case: Track the difference or changes between
consecutive values, like comparing a previous and current value for state
changes.
Example:
import { pairwise } from 'rxjs';
this.value$.pipe(
pairwise() // Emits the previous and current
values as a tuple
).subscribe(([prev, current]) => {
console.log('Previous:', prev, 'Current:',
current);
});
35. What is fromEvent in RxJS, and how is it used in
Angular?
The fromEvent operator is used to create an Observable from DOM events. It is
useful for event handling, such as listening for user interactions like clicks,
mouse movements, or key presses.
Use case: Handle events in Angular components by
subscribing to DOM events using RxJS.
Example:
import { fromEvent } from 'rxjs';
ngOnInit() {
const click$ = fromEvent(document, 'click');
click$.subscribe(event => {
console.log('Document clicked:',
event);
});
}
36. What is the mergeMap operator and how is it different
from switchMap?
- mergeMap:
Maps a source value to an inner Observable and merges all the emissions
from these inner Observables. All inner Observables are subscribed to
concurrently, meaning they are handled in parallel.
- switchMap:
Similar to mergeMap, but with a key difference. It cancels the previous
inner Observable whenever a new value is emitted by the source Observable.
This ensures that only the latest inner Observable is active, making it
suitable for cases like search or user input.
Use case:
- Use
mergeMap for handling concurrent requests.
- Use
switchMap for cases where only the latest operation matters, like live
search.
Example using mergeMap:
this.searchTerm$.pipe(
mergeMap(term =>
this.searchService.search(term))
).subscribe(results => console.log(results));
Example using switchMap:
this.searchTerm$.pipe(
switchMap(term =>
this.searchService.search(term))
).subscribe(results => console.log(results));
37. How can you create an Observable from a Promise in
RxJS?
You can use the from operator to convert a Promise into an Observable. Once the
Promise resolves, the Observable emits the resolved value.
Use case: Use from when you need to integrate
Promise-based APIs with RxJS Observables.
Example:
import { from } from 'rxjs';
const promise = new Promise(resolve => resolve('Data from
Promise'));
from(promise).subscribe(data => {
console.log(data); // Outputs: 'Data from
Promise'
});
38. What is asyncScheduler in RxJS?
The asyncScheduler is one of the schedulers provided by RxJS and it allows you
to schedule tasks asynchronously in the future, based on the event loop. It’s
often used in combination with operators like observeOn or schedule.
Use case: Use asyncScheduler to schedule tasks or
handle deferred operations without blocking the main thread.
Example:
import { asyncScheduler } from 'rxjs';
import { observeOn } from 'rxjs/operators';
this.observable$.pipe(
observeOn(asyncScheduler)
).subscribe(value => {
console.log(value); // The values will be
emitted asynchronously
});
39. What is the difference between forkJoin and zip in
RxJS?
- forkJoin:
Combines multiple Observables and waits for all of them to complete before
emitting an array of their last emitted values. It is only triggered once
all the source Observables complete.
- zip:
Combines multiple Observables and emits the values as arrays of
corresponding emissions from each Observable. It emits only when each
Observable has emitted a value at the same time.
Use case:
- Use
forkJoin when you need the results of multiple Observables once they are
all completed (e.g., when fetching data from multiple endpoints).
- Use
zip when you want to combine values from multiple streams, but you want
them emitted together based on their order.
Example using forkJoin:
import { forkJoin } from 'rxjs';
forkJoin({
data1: this.httpClient.get('/api/data1'),
data2: this.httpClient.get('/api/data2')
}).subscribe(result => {
console.log(result); // { data1: value1, data2:
value2 }
});
Example using zip:
import { zip } from 'rxjs';
zip(this.httpClient.get('/api/data1'),
this.httpClient.get('/api/data2')).subscribe(([data1, data2]) => {
console.log(data1, data2); // Emits as pairs of
corresponding values
});
40. What is retryWhen and how does it differ from retry?
- retry:
Retries a failed Observable a specified number of times. After the
retries, the Observable completes or errors out.
- retryWhen:
Allows for more complex retry logic. It takes a function that can return
an Observable to determine when the retry will happen. You can introduce
delays, conditions, and custom logic for retries.
Use case: Use retryWhen for advanced retry strategies
such as exponential backoff or delayed retries.
Example using retry:
this.httpClient.get('/api/data').pipe(
retry(3) // Retry up to 3 times
).subscribe();
Example using retryWhen:
import { of } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
this.httpClient.get('/api/data').pipe(
retryWhen(errors => errors.pipe(
delay(1000), // Delay
before retrying
take(3) //
Retry 3 times
))
).subscribe();
41. What is concatMap in RxJS, and how does it differ
from mergeMap?
- concatMap:
Maps a source value to an inner Observable and subscribes to each inner
Observable sequentially. It waits for one inner Observable to complete
before subscribing to the next.
- mergeMap:
Maps a source value to an inner Observable and subscribes to all inner
Observables concurrently. This means the emissions from inner Observables
may be interleaved.
Use case:
- Use
concatMap when you need to ensure that the operations happen sequentially,
such as when the order of execution matters (e.g., step-by-step
processing).
- Use
mergeMap when you want to handle multiple operations concurrently.
Example using concatMap:
this.data$.pipe(
concatMap(item =>
this.processItemSequentially(item))
).subscribe(result => console.log(result));
Example using mergeMap:
this.data$.pipe(
mergeMap(item =>
this.processItemConcurrently(item))
).subscribe(result => console.log(result));
42. What is the difference between observeOn and
subscribeOn in RxJS?
- observeOn:
Specifies the scheduler on which the Observable will operate when emitting
values. It controls on which scheduler the Observables' emissions happen.
- subscribeOn:
Specifies the scheduler on which the subscription to the Observable should
occur. It controls on which scheduler the subscription and initialization
logic for the Observable happens.
Use case:
- Use
observeOn to determine when and where values emitted by an Observable will
be observed.
- Use
subscribeOn to control when the subscription to the Observable will be
executed.
Example using observeOn:
import { observeOn, asyncScheduler } from 'rxjs';
this.observable$.pipe(
observeOn(asyncScheduler)
).subscribe(value => console.log(value)); // Emission
happens asynchronously
Example using subscribeOn:
import { subscribeOn, asyncScheduler } from 'rxjs';
this.observable$.pipe(
subscribeOn(asyncScheduler)
).subscribe(value => console.log(value)); // Subscription
starts asynchronously
43. What is withLatestFrom in RxJS?
The withLatestFrom operator combines the latest value from another Observable
with each value emitted by the source Observable. It doesn't subscribe to the
second Observable, but instead waits for the latest emitted value when the
source Observable emits a value.
Use case: It's useful when you need to combine a
value from the source Observable with the most recent value from another
Observable (e.g., combining user input with the latest state).
Example:
import { withLatestFrom } from 'rxjs';
this.source$.pipe(
withLatestFrom(this.latestValue$)
).subscribe(([sourceValue, latestValue]) => {
console.log('Source:', sourceValue, 'Latest:',
latestValue);
});
44. What is the debounceTime operator and when would you
use it in Angular?
The debounceTime operator delays the emissions of an Observable for a specified
amount of time after the most recent emission. It helps in reducing the
frequency of emissions when you expect rapid, repeated inputs, such as
keypresses.
Use case: Commonly used for scenarios like search
input or autocomplete, where you want to wait for the user to finish typing
before making an HTTP request.
Example:
import { debounceTime } from 'rxjs';
this.searchInput$.pipe(
debounceTime(300) // Wait for 300ms of
inactivity before emitting the value
).subscribe(searchTerm => {
this.search(searchTerm); // Perform search after
debounce
});
45. What is tap in RxJS, and when would you use it?
The tap operator allows you to perform side-effects without modifying the
values emitted by the Observable. It's often used for logging, debugging, or
triggering actions that don't affect the flow of the Observable chain.
Use case: Use tap for side-effects like logging,
setting flags, or updating variables.
Example:
import { tap } from 'rxjs';
this.data$.pipe(
tap(data => console.log('Received data:',
data)) // Logging the data without changing it
).subscribe();
46. What does finalize do in RxJS?
The finalize operator is used to execute a side-effect action when the
Observable completes or errors out. It ensures that clean-up actions are
triggered regardless of whether the Observable completes successfully or
encounters an error.
Use case: Commonly used for cleanup tasks, like
hiding loading spinners, after the Observable completes or errors.
Example:
import { finalize } from 'rxjs';
this.httpClient.get('/api/data').pipe(
finalize(() => {
this.loading = false; // Hide the
loading spinner
})
).subscribe();
47. How does shareReplay work in RxJS?
The shareReplay operator is used to share the emissions of an Observable among
multiple subscribers. It also replays the last emitted value to new
subscribers, ensuring that they receive the most recent emission when they
subscribe.
Use case: This is useful in scenarios where you have
multiple consumers for the same data (e.g., caching results) and you want to
avoid re-executing the Observable for each subscriber.
Example:
import { shareReplay } from 'rxjs';
const shared$ = this.httpClient.get('/api/data').pipe(
shareReplay(1) // Replay the last emitted value
to new subscribers
);
shared$.subscribe(data => console.log('Subscriber 1:',
data));
shared$.subscribe(data => console.log('Subscriber 2:',
data)); // Receives the cached data from the first emission
48. What is auditTime in RxJS?
The auditTime operator limits the frequency of emissions from an Observable. It
allows the source Observable to emit values within a specified window, but only
emits the most recent value at the end of each time window.
Use case: It's useful when you need to rate-limit or
throttle user interactions, like limiting the number of API calls during rapid
events.
Example:
import { auditTime } from 'rxjs';
this.input$.pipe(
auditTime(1000) // Emit only the most recent
value every 1000ms
).subscribe(value => {
console.log(value); // User input will be
processed only once every second
});
49. What is merge in RxJS and when would you use it?
The merge operator combines multiple Observables into a single Observable and
emits values from all the Observables concurrently. It does not wait for any
Observable to complete before emitting the next value.
Use case: Use merge when you need to subscribe to
multiple Observables concurrently, for example when handling multiple user
actions or API requests in parallel.
Example:
import { merge } from 'rxjs';
const observable1 = this.dataService.getData1();
const observable2 = this.dataService.getData2();
merge(observable1, observable2).subscribe(result => {
console.log('Result:', result);
});
50. What is takeUntil in RxJS?
The takeUntil operator emits values from the source Observable until a notifier
Observable emits a value. This is useful for unsubscribing from an Observable
based on some external condition or event.
Use case: Often used for unsubscribing from an
Observable when a component is destroyed or a specific event occurs.
Example:
import { takeUntil } from 'rxjs';
const notifier$ = this.destroy$.pipe();
this.data$.pipe(
takeUntil(notifier$) // Will complete the
Observable when notifier$ emits
).subscribe();
51. What is the bufferTime operator in RxJS?
The bufferTime operator collects values emitted by an Observable into an array
within a specified time window and emits those values as an array. After the
time window ends, it emits the buffered values and starts collecting new values
for the next window.
Use case: Useful when you want to batch emissions
over a time window, such as collecting events over a short period and
processing them in bulk.
Example:
import { bufferTime } from 'rxjs';
this.click$.pipe(
bufferTime(3000) // Collect clicks for 3 seconds
).subscribe(clicks => {
console.log('Buffered clicks:', clicks);
});
52. What is switchAll in RxJS, and when would you use it?
The switchAll operator is used to switch from the current inner Observable to a
new inner Observable. When a new inner Observable is emitted, the current one
is unsubscribed from, and the new Observable starts emitting values.
Use case: Use switchAll when you need to cancel the
previous inner Observable and only keep the latest one active. This is useful
for scenarios like live search or switching between different asynchronous
operations.
Example:
import { switchAll } from 'rxjs';
this.searchQuery$.pipe(
switchAll() // Switch to the latest Observable
when a new search query is emitted
).subscribe(results => {
console.log('Search results:', results);
});
53. What is exhaustMap in RxJS, and how does it differ
from switchMap?
- exhaustMap:
Maps a value from the source Observable to an inner Observable, but
ignores new emissions from the source Observable while the current inner
Observable is still running. This means it will only switch to a new inner
Observable once the current one has completed.
- switchMap:
Switches to a new inner Observable every time the source Observable emits
a new value, canceling the previous one.
Use case:
- Use
exhaustMap when you don't want to handle multiple concurrent requests
(e.g., submitting a form only once until the previous submission is
complete).
- Use
switchMap when you only care about the latest emission, and cancel
previous emissions.
Example using exhaustMap:
import { exhaustMap } from 'rxjs';
this.formSubmit$.pipe(
exhaustMap(() => this.submitForm())
).subscribe(result => {
console.log('Form submitted successfully:',
result);
});
Example using switchMap:
import { switchMap } from 'rxjs';
this.formSubmit$.pipe(
switchMap(() => this.submitForm())
).subscribe(result => {
console.log('Form submitted with latest data:',
result);
});
54. What is repeatWhen in RxJS?
The repeatWhen operator allows you to repeat an Observable based on the
emissions of another Observable. It gives you control over when the source
Observable should repeat by using the notifier Observable.
Use case: Use repeatWhen when you need to trigger the
repetition of an Observable based on custom logic, such as retrying an
operation or looping until a condition is met.
Example:
import { repeatWhen, delay } from 'rxjs';
this.httpClient.get('/api/data').pipe(
repeatWhen(notifications =>
notifications.pipe(
delay(2000) // Repeat the request
every 2 seconds
))
).subscribe(data => {
console.log('Fetched data:', data);
});
55. What is the difference between concat and concatMap
in RxJS?
- concat:
Combines multiple Observables into a single Observable and emits their
values sequentially, waiting for each Observable to complete before moving
on to the next one.
- concatMap:
Maps each value from the source Observable to an inner Observable and
subscribes to each inner Observable one by one, ensuring sequential
emission.
Use case:
- Use
concat to concatenate multiple Observables together and ensure their
emissions happen in sequence.
- Use
concatMap when you need to map each source emission to an inner Observable
and ensure their sequential execution.
Example using concat:
import { concat } from 'rxjs';
const observable1 = this.httpClient.get('/api/first');
const observable2 = this.httpClient.get('/api/second');
concat(observable1, observable2).subscribe(data => {
console.log('Received data:', data);
});
Example using concatMap:
import { concatMap } from 'rxjs';
this.data$.pipe(
concatMap(item => this.fetchData(item))
).subscribe(data => {
console.log('Fetched data:', data);
});
56. What is share in RxJS, and when would you use it?
The share operator is a shorthand for combining the behavior of multicast and
refCount to share the source Observable. It allows multiple subscribers to
share the same Observable execution, preventing the source Observable from
being executed multiple times.
Use case: Use share when you want to share a single
subscription to an Observable across multiple subscribers, like caching the
result of an HTTP request and preventing multiple network calls.
Example:
import { share } from 'rxjs';
const shared$ = this.httpClient.get('/api/data').pipe(
share()
);
shared$.subscribe(data => console.log('Subscriber 1:',
data));
shared$.subscribe(data => console.log('Subscriber 2:',
data)); // Shared subscription
57. What is delayWhen in RxJS?
The delayWhen operator delays the emission of values from the source Observable
based on the emission of another Observable. You can specify how long to delay
using a notifier Observable.
Use case: Use delayWhen when you want to delay values
based on a dynamic condition (e.g., waiting for some external event or timer).
Example:
import { delayWhen, timer } from 'rxjs';
this.source$.pipe(
delayWhen(() => timer(1000)) // Delay by 1
second for each emission
).subscribe(value => {
console.log('Delayed value:', value);
});
58. What is debounce vs debounceTime in RxJS?
- debounceTime:
Delays the emission of values for a specified amount of time after the
most recent emission, ensuring that only the final value in a burst of
emissions is emitted after the specified time.
- debounce:
Similar to debounceTime, but instead of using a fixed time, it allows you
to specify a custom logic to return an Observable that defines how long to
wait before emitting the value.
Use case:
- Use
debounceTime for simple, time-based debounce scenarios (e.g., for search
inputs).
- Use
debounce for more complex or dynamic debounce behavior where the delay
might depend on the emitted values.
Example using debounceTime:
import { debounceTime } from 'rxjs';
this.search$.pipe(
debounceTime(300) // Wait for 300ms of
inactivity
).subscribe(query => {
console.log('Search query:', query);
});
Example using debounce:
import { debounce } from 'rxjs';
this.search$.pipe(
debounce(() => this.api.getDelay()) // Delay
based on the response from another API call
).subscribe(query => {
console.log('Search query:', query);
});
59. What is race in RxJS?
The race operator takes multiple Observables as input and emits values from the
first Observable that emits a value. If one of the Observables emits a value
first, the rest are ignored.
Use case: Use race when you need to select the
fastest Observable from multiple sources, like fetching data from multiple APIs
and using the first response.
Example:
import { race, of, timer } from 'rxjs';
const fastest$ = race(
timer(1000, 2000),
timer(500, 1000)
);
fastest$.subscribe(value => {
console.log('The fastest Observable emitted:',
value);
});
60. How does bufferCount work in RxJS?
The bufferCount operator collects values into an array and emits the array once
the specified number of values have been emitted. After each emission, a new
buffer is started.
Use case: Use bufferCount when you need to group
emissions into fixed-size chunks, for example, batching API requests in groups
of a specific size.
Example:
import { bufferCount } from 'rxjs';
this.data$.pipe(
bufferCount(3) // Emit every 3 values as an
array
).subscribe(values => {
console.log('Buffered values:', values);
});
61. What is combineLatest in RxJS and when would you use
it?
The combineLatest operator combines the latest values from multiple
Observables. It waits for each Observable to emit at least one value, and then
emits the latest values from each of the provided Observables every time any of
them emits.
Use case: Use combineLatest when you need to combine
values from multiple sources and react to any change in the latest emissions.
It’s useful for scenarios like combining form input values, user preferences,
or state updates.
Example:
import { combineLatest } from 'rxjs';
combineLatest([this.observable1$,
this.observable2$]).subscribe(([value1, value2]) => {
console.log('Latest values:', value1, value2);
});
62. What is startWith in RxJS?
The startWith operator emits a specified value before any values from the
source Observable are emitted. This is useful when you want to initialize a
stream with a default value.
Use case: Use startWith when you need to emit a
default value or trigger a state update immediately when an Observable is
subscribed to.
Example:
import { startWith } from 'rxjs';
this.data$.pipe(
startWith('Initial value') // Emit 'Initial
value' first before any other emissions
).subscribe(value => {
console.log('Emitted:', value);
});
63. What is groupBy in RxJS and when should you use it?
The groupBy operator groups the emitted values from the source Observable into
multiple inner Observables based on a key. Each group emits values associated
with the group’s key, which can be processed independently.
Use case: Use groupBy when you need to process
grouped data, such as categorizing user activities, items in a shopping cart,
or events based on some attribute (e.g., grouping items by category).
Example:
import { groupBy, mergeMap } from 'rxjs';
this.items$.pipe(
groupBy(item => item.category),
mergeMap(group$ => group$.pipe(
// Process each group (category)
separately
map(group => ({ category:
group.key, items: group }))
))
).subscribe(result => {
console.log(result); // Processed categories and
their items
});
64. What is takeWhile in RxJS and how does it differ from
takeUntil?
- takeWhile:
Emits values from the source Observable until a provided condition returns
false. It stops emitting values as soon as the condition becomes false,
but it can emit values while the condition is true.
- takeUntil:
Emits values from the source Observable until another Observable emits a
value (usually a notifier), at which point it stops.
Use case:
- Use
takeWhile when you want to stop emitting values based on a condition.
- Use
takeUntil when you want to stop emitting values when a specific notifier
Observable emits.
Example using takeWhile:
import { takeWhile } from 'rxjs';
this.data$.pipe(
takeWhile(item => item < 10) // Stop
emitting if item is >= 10
).subscribe(value => {
console.log(value);
});
Example using takeUntil:
import { takeUntil } from 'rxjs';
this.data$.pipe(
takeUntil(this.stop$) // Stop emitting when
`stop$` emits
).subscribe(value => {
console.log(value);
});
65. What is mergeScan in RxJS?
The mergeScan operator is similar to scan, but it allows for concurrent
execution of the inner Observables. It accumulates a state based on the
emissions of an inner Observable while merging multiple inner Observables.
Unlike concatMap, which executes inner Observables sequentially, mergeScan
allows for concurrent inner emissions.
Use case: Use mergeScan when you want to maintain a
running state based on emissions from multiple concurrent inner Observables,
such as accumulating results from multiple network requests.
Example:
import { mergeScan } from 'rxjs';
this.data$.pipe(
mergeScan((acc, item) =>
this.fetchData(item).pipe(map(res => acc + res)), 0) // Accumulate results
).subscribe(result => {
console.log('Accumulated result:', result);
});
66. What is retryWhen in RxJS and how does it differ from
retry?
- retry:
Automatically retries the source Observable a specified number of times if
it fails (e.g., due to an error), without any conditions or delay.
- retryWhen:
Allows you to specify a custom retry strategy by providing a function that
returns an Observable. This Observable can emit values that determine when
to retry and if the retry should happen at all.
Use case:
- Use
retry for simple retry scenarios where you want to retry a fixed number of
times after an error.
- Use
retryWhen for more complex retry strategies, such as delaying retries,
exponential backoff, or conditional retries based on specific error types.
Example using retry:
import { retry } from 'rxjs';
this.http$.pipe(
retry(3) // Retry up to 3 times in case of an
error
).subscribe(result => console.log(result));
Example using retryWhen:
import { retryWhen, delay, take, concatMap } from 'rxjs';
this.http$.pipe(
retryWhen(errors =>
errors.pipe(
concatMap((e, i) => i
< 3 ? of(e).pipe(delay(1000)) : throwError(e))
)
)
).subscribe(result => console.log(result));
67. What is timeout in RxJS and how do you handle a
timeout?
The timeout operator is used to throw an error if the source Observable does
not emit a value within a specified time period. It is commonly used to handle
situations where you expect an Observable to emit values within a certain time
frame, like network requests or long-running operations.
Use case: Use timeout to avoid waiting indefinitely
for a response and to handle timeout errors in a more controlled way.
Example:
import { timeout, throwError } from 'rxjs';
this.http$.pipe(
timeout(5000) // Timeout after 5 seconds if no
value is emitted
).subscribe({
next: value => console.log('Value received:',
value),
error: err => console.log('Error:', err) //
Handle timeout error
});
68. What is shareReplay and how does it help in caching?
The shareReplay operator ensures that multiple subscribers to an Observable
receive the most recent emitted value, even if they subscribe at different
times. It caches the most recent value (or a specified number of values) and
replays them to new subscribers.
Use case: Use shareReplay when you need to cache data
(e.g., HTTP responses) and avoid making multiple network requests for the same
data.
Example:
import { shareReplay } from 'rxjs';
const shared$ = this.http$.pipe(
shareReplay(1) // Cache the most recent value
and replay it to new subscribers
);
shared$.subscribe(data => {
console.log('Subscriber 1:', data); // Receives
the cached data
});
shared$.subscribe(data => {
console.log('Subscriber 2:', data); // Receives
the cached data as well
});
69. What is zip in RxJS?
The zip operator combines the emissions of multiple Observables into a single
Observable. It waits for all of the provided Observables to emit at least one
value, and then it combines their emissions into an array (or custom function)
and emits the combined values as a new array.
Use case: Use zip when you want to combine multiple
Observables and handle the values from all of them in a synchronized way.
Example:
import { zip } from 'rxjs';
zip(this.observable1$,
this.observable2$).subscribe(([value1, value2]) => {
console.log('Combined values:', value1, value2);
});
70. What is switchMapTo in RxJS?
The switchMapTo operator is similar to switchMap, but instead of mapping the
source value to an Observable, it simply switches to a given Observable. It
allows you to map the source value to an Observable without using that value.
Use case: Use switchMapTo when you want to switch to
a fixed Observable when the source emits, without needing to map the source
value to a new Observable.
Example:
import { switchMapTo } from 'rxjs';
this.source$.pipe(
switchMapTo(this.httpClient.get('/api/data')) //
Switch to the Observable returned by the HTTP request
).subscribe(response => {
console.log('Response:', response);
});
71. What is toPromise in RxJS, and how does it differ
from firstValueFrom and lastValueFrom?
- toPromise:
Converts an Observable into a Promise. It waits for the first emitted
value and resolves the Promise with that value.
- firstValueFrom:
Converts an Observable to a Promise, but explicitly resolves with the
first value emitted by the Observable. It works similarly to toPromise,
but it’s part of the rxjs package and recommended for new code.
- lastValueFrom:
Converts an Observable into a Promise that resolves with the last emitted
value.
Use case:
- Use
toPromise or firstValueFrom when you need to convert an Observable to a
Promise for a specific value (e.g., when working with async/await syntax).
- Use
lastValueFrom when you want the Promise to resolve with the last emitted
value of the Observable.
Example with firstValueFrom:
import { firstValueFrom } from 'rxjs';
async function fetchData() {
const data = await
firstValueFrom(this.http$.pipe(
take(1)
));
console.log(data);
}
72. What is partition in RxJS and how does it work?
The partition operator splits an Observable into two Observables based on a
condition. The first Observable emits values that satisfy the condition, and
the second emits values that do not satisfy the condition.
Use case: Use partition when you need to separate
data into two streams based on a specific condition, like filtering active vs
inactive users.
Example:
import { partition } from 'rxjs';
const [active$, inactive$] = partition(this.users$, user
=> user.isActive);
active$.subscribe(user => console.log('Active user:',
user));
inactive$.subscribe(user => console.log('Inactive user:',
user));
73. What is buffer in RxJS, and how does it differ from
bufferCount?
- buffer:
Collects values from the source Observable into an array and emits the
array whenever another Observable emits a value (the notifier). The values
are buffered until the notifier emits.
- bufferCount:
Collects values into an array and emits it after a specified number of
values have been collected.
Use case: Use buffer when you want to buffer
emissions based on another Observable’s emissions, and use bufferCount when you
want to collect a fixed number of values into an array.
Example using buffer:
import { buffer } from 'rxjs';
this.source$.pipe(
buffer(this.otherSource$) // Buffer values until
`otherSource$` emits
).subscribe(values => {
console.log('Buffered values:', values);
});
Example using bufferCount:
import { bufferCount } from 'rxjs';
this.source$.pipe(
bufferCount(3) // Buffer 3 items and emit them
as an array
).subscribe(values => {
console.log('Buffered values:', values);
});
74. What is finalize in RxJS, and how is it different
from complete?
The finalize operator is executed when an Observable completes or errors. It
allows you to execute some final logic (like cleanup) regardless of whether the
Observable successfully completes or errors.
- complete:
Is a notification sent by an Observable to indicate that it has completed
and will emit no further values.
- finalize:
Is called after the Observable completes or errors. It’s useful for
cleanup operations (e.g., stopping loading spinners).
Use case: Use finalize when you need to perform final
operations like hiding a loading indicator, logging, or cleanup tasks.
Example:
import { finalize } from 'rxjs';
this.http$.pipe(
finalize(() => {
console.log('Request completed or
failed!');
})
).subscribe();
75. What is takeLast in RxJS, and how does it work?
The takeLast operator emits the last n values emitted by the source Observable
before completing. This is useful when you want to retrieve only the last few
emitted values.
Use case: Use takeLast when you are only interested
in the last few emitted values from a stream.
Example:
import { takeLast } from 'rxjs';
this.source$.pipe(
takeLast(3) // Take the last 3 emitted values
).subscribe(value => {
console.log('Last value:', value);
});
76. What is ignoreElements in RxJS?
The ignoreElements operator ignores all emissions from the source Observable
and only lets notifications (complete or error) propagate. It is useful when
you care only about completion or error, and you don’t need the actual emitted
values.
Use case: Use ignoreElements when you don’t care
about the emitted values but just need to react to completion or error
notifications.
Example:
import { ignoreElements } from 'rxjs';
this.source$.pipe(
ignoreElements() // Ignore emitted values, but
still complete or error
).subscribe({
complete: () => console.log('Source
Observable completed'),
error: (err) => console.log('Error:', err)
});
77. What is pluck in RxJS?
The pluck operator extracts a specific property from each emitted value,
returning an Observable of the values of that property. This is especially
useful when working with objects.
Use case: Use pluck when you want to extract specific
properties from an object emitted by the source Observable.
Example:
import { pluck } from 'rxjs';
this.users$.pipe(
pluck('name') // Extract the `name` property
from each emitted user object
).subscribe(name => {
console.log('User name:', name);
});
78. What is auditTime in RxJS, and how does it differ
from debounceTime?
- auditTime:
Emits the most recent value from the source Observable after a specified
time period, but it ignores any new emissions while the timer is running.
After the specified period, it emits the latest value.
- debounceTime:
Emits the last value emitted by the source Observable after a period of
inactivity. If there is a new value before the debounce time finishes, it
resets the timer.
Use case:
- Use
auditTime when you want to emit the most recent value at fixed intervals,
even if new values are being emitted before the interval completes.
- Use
debounceTime when you want to wait until the user stops emitting values
for a specified time (e.g., for live search).
Example using auditTime:
import { auditTime } from 'rxjs';
this.source$.pipe(
auditTime(500) // Emit the most recent value
every 500ms
).subscribe(value => {
console.log('Emitted:', value);
});
79. What is withLatestFrom in RxJS?
The withLatestFrom operator combines the latest value from another Observable
with the values from the source Observable. It allows you to create a stream
that includes values from both the source and the provided Observable.
Use case: Use withLatestFrom when you want to merge
the latest value from one stream with another stream of values.
Example:
import { withLatestFrom } from 'rxjs';
this.click$.pipe(
withLatestFrom(this.latestData$) // Combine
click events with the latest data
).subscribe(([click, data]) => {
console.log('Click event:', click, 'Latest
data:', data);
});
80. What is expand in RxJS?
The expand operator is used for recursive processing. It applies a function to
the value emitted by the source Observable and returns an Observable. This
Observable can emit further values, which are then passed through the function
recursively.
Use case: Use expand when you want to recursively
apply a function to a value until a condition is met, for example, paginating
through an API.
Example:
import { expand, takeWhile } from 'rxjs';
this.page$.pipe(
expand(page => this.loadPage(page + 1)), //
Recursively load next page
takeWhile(page => page <= 5) // Stop after
5 pages
).subscribe(page => {
console.log('Loading page:', page);
});
81. What is concatMap in RxJS, and how is it different
from mergeMap?
- concatMap:
Transforms values from the source Observable by mapping them to inner
Observables. It subscribes to each inner Observable one at a time,
ensuring that each one completes before moving on to the next. This
guarantees sequential execution.
- mergeMap:
Also maps values from the source Observable to inner Observables, but
subscribes to all of them concurrently, emitting values as they arrive
from the inner Observables.
Use case:
- Use
concatMap when the order of execution is important, and you need to
process inner Observables sequentially (e.g., when submitting forms one at
a time).
- Use
mergeMap when you don’t care about the order and want concurrent execution
for efficiency (e.g., making multiple HTTP requests simultaneously).
Example using concatMap:
import { concatMap } from 'rxjs';
this.source$.pipe(
concatMap(value => this.fetchData(value)) //
Sequential processing of each value
).subscribe(result => {
console.log('Processed sequentially:', result);
});
Example using mergeMap:
import { mergeMap } from 'rxjs';
this.source$.pipe(
mergeMap(value => this.fetchData(value)) //
Concurrent processing of each value
).subscribe(result => {
console.log('Processed concurrently:', result);
});
82. What is retryWhen in RxJS, and how does it differ
from retry?
- retryWhen:
Allows you to define a custom retry strategy by providing a function that
takes an error Observable and returns an Observable that determines when
the retry should happen. You can include backoff strategies, delays, and
conditions.
- retry:
A simpler operator that automatically retries the Observable a fixed
number of times without any custom logic or delay.
Use case:
- Use
retry for straightforward retry logic where you want to retry a fixed
number of times on error.
- Use
retryWhen when you need more control over the retry behavior, such as
adding delays or handling specific error types.
Example using retry:
import { retry } from 'rxjs';
this.http$.pipe(
retry(3) // Retry the operation 3 times in case
of error
).subscribe({
next: result => console.log(result),
error: err => console.log('Error:', err)
});
Example using retryWhen:
import { retryWhen, delay, concatMap } from 'rxjs';
this.http$.pipe(
retryWhen(errors =>
errors.pipe(
concatMap((error, index)
=> index < 3 ? of(error).pipe(delay(1000)) : throwError(error))
)
)
).subscribe({
next: result => console.log(result),
error: err => console.log('Error:', err)
});
83. What is zipAll in RxJS and how does it differ from
combineLatest?
- zipAll:
Converts an Observable of Observables into an Observable that emits arrays
of values, where each array corresponds to the emitted values from the
inner Observables at the same index.
- combineLatest:
Emits the latest values from multiple Observables as they emit, without
waiting for them to emit at the same time. It emits a new value every time
any of the Observables emits.
Use case:
- Use
zipAll when you want to combine values from multiple Observables but only
emit them when each Observable has emitted its corresponding value. It’s
useful for synchronizing emissions from multiple streams.
- Use
combineLatest when you want to combine the latest emitted values from each
stream, regardless of when they were emitted.
Example using zipAll:
import { zipAll } from 'rxjs';
const observable1$ = of(1, 2, 3);
const observable2$ = of('a', 'b', 'c');
observable1$.pipe(
zipAll() // Combines values at the same index
from all inner Observables
).subscribe(([value1, value2]) => {
console.log(value1, value2);
});
84. What is exhaustMap in RxJS?
The exhaustMap operator is used to map the values emitted by the source
Observable to inner Observables, but it ignores any subsequent values while the
inner Observable is still active. In other words, it "exhausts" all
emissions from the source Observable by ignoring new emissions until the
current inner Observable completes.
Use case: Use exhaustMap when you want to process the
first value from the source and ignore subsequent values until the current
operation completes (e.g., for form submissions or API calls that should not be
triggered multiple times).
Example:
import { exhaustMap } from 'rxjs';
this.click$.pipe(
exhaustMap(() => this.makeRequest()) //
Ignore subsequent clicks while a request is ongoing
).subscribe(response => {
console.log('Response received:', response);
});
85. What is takeUntil in RxJS?
The takeUntil operator is used to take values from the source Observable until
a notifier Observable emits a value. After the notifier emits, the source
Observable completes.
Use case: Use takeUntil to stop the subscription when
a specific event occurs, such as when a user navigates away or when a timeout
occurs.
Example:
import { takeUntil } from 'rxjs';
this.source$.pipe(
takeUntil(this.stop$) // Stop emitting values
when `stop$` emits
).subscribe(value => {
console.log(value);
});
86. What is fromEvent in RxJS and how do you use it?
The fromEvent operator creates an Observable that listens for events of a
specific type on a given DOM element or Node. This allows you to handle events
such as clicks, keypresses, or mouse movements in a declarative way.
Use case: Use fromEvent when you need to handle DOM
events reactively (e.g., handling user input or mouse events).
Example:
import { fromEvent } from 'rxjs';
const button = document.querySelector('button');
fromEvent(button, 'click').subscribe(() => {
console.log('Button clicked');
});
87. What is combineAll in RxJS?
The combineAll operator takes an Observable of Observables and combines all the
values from the inner Observables into a single Observable. It waits for all
inner Observables to complete and then emits an array of the last emitted
values.
Use case: Use combineAll when you have an Observable
of Observables and you need to gather the final emitted values from each inner
Observable into an array after all have completed.
Example:
import { combineAll } from 'rxjs';
const observableOfObservables$ = of(of(1, 2), of(3, 4));
observableOfObservables$.pipe(
combineAll() // Combine all emitted values from
the inner Observables
).subscribe(values => {
console.log(values); // [2, 4]
});
88. What is race in RxJS?
The race operator takes multiple Observables and emits values from the first
Observable to emit a value. It "races" through the Observables and
subscribes to the first one that emits, then ignores the rest.
Use case: Use race when you want to choose between
multiple competing sources of data and only care about the first one to emit.
Example:
import { race, of } from 'rxjs';
const observable1$ = of('A').pipe(delay(1000));
const observable2$ = of('B').pipe(delay(500));
race(observable1$, observable2$).subscribe(value => {
console.log(value); // 'B' because it emitted
first
});
89. What is window in RxJS?
The window operator emits an Observable that contains the values from the
source Observable as its "window" of emitted values. It opens a new
"window" each time the source emits, and the window emits the values
from the source.
Use case: Use window when you want to group values
into multiple Observables (windows), allowing you to process them separately.
Example:
import { window, map } from 'rxjs';
this.source$.pipe(
window(this.window$), // Group values based on
another Observable's emissions
map(window$ => window$.toArray()) // Convert
each window to an array of values
).subscribe(values => {
console.log('Window values:', values);
});
90. What is debounceTime in RxJS, and when should you use
it?
The debounceTime operator ensures that a value is only emitted after the source
Observable has been silent for a specified amount of time. It is typically used
to delay emissions and prevent rapid, repeated actions, such as user
keystrokes.
Use case: Use debounceTime for scenarios where you
want to wait until the user stops typing or an event stops firing before
performing an action (e.g., in search bars or form validations).
Example:
import { debounceTime } from 'rxjs';
this.searchInput$.pipe(
debounceTime(300) // Wait for 300ms of silence
before emitting the latest value
).subscribe(value => {
console.log('Search query:', value);
});
91. What is catchError in RxJS, and how is it used?
The catchError operator is used to catch errors that occur during the stream's
execution and allows you to handle or recover from those errors. It catches
errors emitted by the source Observable and provides an alternative Observable
(a fallback stream).
Use case: Use catchError when you want to handle
errors in a stream, such as providing a default value or retrying the
operation.
Example:
import { catchError } from 'rxjs';
this.http$.pipe(
catchError(err => {
console.error('Error:', err);
return of('Fallback value'); //
Return an observable with a fallback value
})
).subscribe(result => {
console.log('Result:', result); // 'Fallback
value' in case of error
});
92. What is tap in RxJS, and how does it differ from map?
- tap:
The tap operator is a side-effect operator. It allows you to perform
actions (like logging or debugging) on the emitted values without
modifying them. It does not alter the stream and simply passes the values
through unchanged.
- map:
The map operator is used to transform the emitted values by applying a
function to each value, creating a new value.
Use case:
- Use
tap for side effects like logging, debugging, or triggering actions that
do not affect the stream’s flow.
- Use
map when you need to transform the emitted value before passing it along.
Example using tap:
import { tap } from 'rxjs';
this.source$.pipe(
tap(value => console.log('Side effect:',
value)) // Log values without changing them
).subscribe();
93. What is pairwise in RxJS?
The pairwise operator emits an array of two consecutive values from the source
Observable. It will emit the previous and current value as an array each time a
new value is emitted.
Use case: Use pairwise when you need to compare
consecutive values from a stream, like calculating changes in data or comparing
the previous and current values in a stream.
Example:
import { pairwise } from 'rxjs';
this.source$.pipe(
pairwise() // Emit consecutive pairs of values
).subscribe(([prev, curr]) => {
console.log('Previous:', prev, 'Current:',
curr);
});
94. What is shareReplay in RxJS?
The shareReplay operator multicasts the source Observable and shares the
emitted values among multiple subscribers. It also caches the most recent
emitted values, replaying them to new subscribers when they subscribe, based on
a specified buffer size.
Use case: Use shareReplay when you want to share the
result of an Observable and avoid making repeated requests or re-running
expensive operations.
Example:
import { shareReplay } from 'rxjs';
this.http$.pipe(
shareReplay(1) // Cache the most recent value
and share it with new subscribers
).subscribe(result => {
console.log('Result:', result);
});
95. What is mergeAll in RxJS?
The mergeAll operator subscribes to each inner Observable emitted by the source
Observable concurrently, and emits all values from those inner Observables in
the order they arrive.
Use case: Use mergeAll when you have an Observable
that emits Observables and you want to merge all the emissions from these inner
Observables into a single stream.
Example:
import { mergeAll } from 'rxjs';
this.source$.pipe(
mergeAll() // Merge values from all emitted
Observables
).subscribe(value => {
console.log('Merged value:', value);
});
96. What is groupBy in RxJS?
The groupBy operator groups the emissions from the source Observable based on a
key. It emits a grouped Observable for each distinct key, which you can then
process individually.
Use case: Use groupBy when you want to group items
based on some criteria and then process each group separately (e.g., grouping
users by their city).
Example:
import { groupBy, mergeMap, map } from 'rxjs';
this.users$.pipe(
groupBy(user => user.city), // Group users by
city
mergeMap(group$ => group$.pipe(
map(user => user.name)
)) // Process each group
).subscribe(name => {
console.log('User name:', name);
});
97. What is takeWhile in RxJS, and how does it work?
The takeWhile operator emits values from the source Observable as long as a
specified condition is true. Once the condition becomes false, it completes the
stream.
Use case: Use takeWhile when you need to filter the
stream until a certain condition is met, such as stopping data collection after
a specific value.
Example:
import { takeWhile } from 'rxjs';
this.source$.pipe(
takeWhile(value => value < 10) // Take
values until the value is no longer less than 10
).subscribe(value => {
console.log(value);
});
98. What is debounce in RxJS, and how does it differ from
debounceTime?
- debounceTime:
Waits for a specific duration of inactivity before emitting the most
recent value. It is typically used for scenarios like waiting for a user
to stop typing in a search bar before firing an API request.
- debounce:
Similar to debounceTime, but instead of waiting for a fixed duration, it
waits for an Observable (often based on a time-based condition) to emit
before continuing. It provides more flexibility, like custom delays or
timeouts.
Use case:
- Use
debounceTime for simple debounce scenarios with a fixed delay.
- Use
debounce for more complex scenarios where the debounce condition is
dynamic.
Example using debounce:
import { debounce } from 'rxjs';
this.source$.pipe(
debounce(() => this.getDebounceDelay()) //
Custom debounce logic based on another Observable
).subscribe(value => {
console.log('Debounced value:', value);
});
99. What is retry in RxJS, and how does it work?
The retry operator retries the source Observable a specified number of times
when it encounters an error. If the Observable still errors after the specified
number of retries, the error will propagate.
Use case: Use retry when you want to automatically
retry an operation a certain number of times before propagating the error, such
as retrying a failed network request.
Example:
import { retry } from 'rxjs';
this.http$.pipe(
retry(3) // Retry the request 3 times if it
fails
).subscribe({
next: result => console.log('Result:',
result),
error: err => console.log('Error:', err)
});
100. What is defaultIfEmpty in RxJS?
The defaultIfEmpty operator emits a default value if the source Observable
completes without emitting any values. This can be useful when you want to
ensure that a value is emitted even when the source Observable is empty.
Use case: Use defaultIfEmpty when you want to provide
a fallback value if the Observable completes without emitting anything.
Example:
import { defaultIfEmpty } from 'rxjs';
this.source$.pipe(
defaultIfEmpty('No values emitted') // Emit a
default value if the source is empty
).subscribe(value => {
console.log(value); // 'No values emitted' if
the source is empty
});
101. What is from in RxJS, and when would you use it?
The from operator is used to convert various types of data (arrays, promises,
iterables, or observables) into an Observable. It enables handling
non-Observable data in a reactive manner.
Use case: Use from when you need to convert an array,
promise, or other iterable to an Observable to work with it reactively.
Example:
import { from } from 'rxjs';
// Convert an array into an Observable
from([1, 2, 3]).subscribe(value => {
console.log(value); // 1, 2, 3
});
// Convert a promise into an Observable
from(Promise.resolve('Hello')).subscribe(value => {
console.log(value); // 'Hello'
});
102. What is switchAll in RxJS?
The switchAll operator subscribes to each Observable emitted by the source
Observable. It cancels the previous inner Observable whenever a new inner
Observable is emitted, making it useful for scenarios where only the latest
inner Observable’s emissions matter.
Use case: Use switchAll when you need to switch to a
new inner Observable and cancel the previous one, such as in search
auto-completion or live updates where only the latest result is needed.
Example:
import { switchAll, map, of } from 'rxjs';
this.search$.pipe(
map(query => this.searchApi(query)), // Emits
an Observable from the API
switchAll() // Switch to the latest search
Observable and cancel previous ones
).subscribe(result => {
console.log(result); // Latest search result
});
103. What is concatAll in RxJS, and when should you use
it?
The concatAll operator subscribes to each Observable emitted by the source
Observable one at a time, ensuring that it processes them sequentially (i.e.,
the next Observable starts only after the previous one completes).
Use case: Use concatAll when you need to sequentially
process multiple Observables, ensuring that one completes before the next one
starts (e.g., processing a batch of tasks in sequence).
Example:
import { concatAll } from 'rxjs';
this.source$.pipe(
concatAll() // Process all emitted Observables
sequentially
).subscribe(result => {
console.log(result); // Sequentially processed
values
});
104. What is bufferTime in RxJS?
The bufferTime operator collects values emitted by the source Observable into
an array, which is emitted after a specified period of time. It works by
"buffering" values over a time interval and emitting them as an array
when the time window is complete.
Use case: Use bufferTime when you need to collect
values over a period and then emit them as an array after the time window
elapses, such as gathering a set of values for batch processing.
Example:
import { bufferTime } from 'rxjs';
this.source$.pipe(
bufferTime(2000) // Collect values every 2
seconds into an array
).subscribe(values => {
console.log(values); // Array of values emitted
every 2 seconds
});
105. What is expand in RxJS?
The expand operator recursively projects each value from the source Observable
into a new Observable, then subscribes to that new Observable and repeats the
process until a condition is met. It's like map, but it works recursively to
emit new values over time.
Use case: Use expand when you need to generate a
recursive series of values (like pagination or tree traversal) based on
previous values.
Example:
import { expand, takeWhile } from 'rxjs';
this.source$.pipe(
expand(value => this.getNextValue(value)), //
Recursively call getNextValue
takeWhile(value => value < 10) // Stop the
recursion once the value reaches 10
).subscribe(result => {
console.log(result); // Recursively emitted
values
});
106. What is first in RxJS?
The first operator emits the first value from the source Observable that meets
a given condition. If no condition is provided, it emits the first value
emitted by the source. If no value is emitted, it can return a default value or
throw an error.
Use case: Use first when you only care about the
first value emitted by the Observable or when you need to limit emissions to
just the first valid value.
Example:
import { first } from 'rxjs';
this.source$.pipe(
first(value => value > 5, 'No value
found') // Emit the first value greater than 5, or a default
).subscribe(result => {
console.log(result); // The first value greater
than 5, or 'No value found'
});
107. What is combineLatestWith in RxJS?
The combineLatestWith operator combines the emissions of the source Observable
with those of another Observable. It emits the latest values from both
Observables every time either of them emits.
Use case: Use combineLatestWith when you want to
combine the latest values from multiple streams and react to changes in any of
them.
Example:
import { combineLatestWith, of } from 'rxjs';
this.source$.pipe(
combineLatestWith(of('A', 'B')) // Combine
values from source$ and an array of values
).subscribe(([sourceValue, combinedValue]) => {
console.log('Source:', sourceValue, 'Combined:',
combinedValue);
});
108. What is finalize in RxJS?
The finalize operator allows you to perform cleanup actions (like closing
resources or logging) when an Observable completes or errors. It will always be
executed regardless of whether the Observable successfully completes or emits
an error.
Use case: Use finalize for cleanup tasks that need to
occur regardless of the completion state of the Observable (e.g., stopping
loading indicators, closing connections).
Example:
import { finalize } from 'rxjs';
this.source$.pipe(
finalize(() => console.log('Observable has
completed or errored'))
).subscribe({
next: value => console.log(value),
error: err => console.log('Error:', err)
});
109. What is raceWith in RxJS?
The raceWith operator is used to subscribe to two or more Observables and emit
values from the first Observable that emits a value. It "races" the
Observables and whichever emits first wins.
Use case: Use raceWith when you want to handle
multiple competing Observables and react to the first one that emits.
Example:
import { raceWith, of, timer } from 'rxjs';
const source$ = timer(1000);
const race$ = of('First wins!');
source$.pipe(
raceWith(race$) // race against `race$` and emit
the first one to win
).subscribe(result => {
console.log(result); // 'First wins!' because
`race$` emits first
});
110. What is throttleTime in RxJS, and how does it differ
from debounceTime?
- throttleTime:
Emits the first value from the source Observable, then ignores all
subsequent values for a specified duration. It essentially
"throttles" the stream, ensuring that emissions are spaced out.
- debounceTime:
Waits for a period of inactivity after the last emitted value before
emitting the most recent value.
Use case:
- Use
throttleTime when you want to emit a value at regular intervals, ensuring
that rapid emissions are ignored.
- Use
debounceTime when you want to wait for silence before emitting the latest
value (useful in search bars or typeahead features).
Example using throttleTime:
import { throttleTime } from 'rxjs';
this.source$.pipe(
throttleTime(1000) // Emit only the first value
in every 1-second interval
).subscribe(value => {
console.log(value); // First value every 1
second
});
111. What is bufferCount in RxJS?
The bufferCount operator collects values from the source Observable in batches
of a specified size and emits them as an array when the batch is complete.
Use case: Use bufferCount when you want to collect
values into chunks and process them in groups rather than individually (e.g.,
batching requests).
Example:
import { bufferCount } from 'rxjs';
this.source$.pipe(
bufferCount(3) // Group values into batches of 3
).subscribe(values => {
console.log(values); // Array of values in
batches of 3
});
112. What is startWith in RxJS?
The startWith operator allows you to prepend an initial value to the source
Observable’s emissions. It emits the specified value before the source
Observable starts emitting.
Use case: Use startWith when you need to provide an
initial value, such as when you want to provide a loading state before actual
data is emitted.
Example:
import { startWith } from 'rxjs';
this.source$.pipe(
startWith('Loading...') // Emit 'Loading...'
before any values from the source
).subscribe(value => {
console.log(value); // 'Loading...' first, then
source values
});
113. What is zip in RxJS and how does it work?
The zip operator combines multiple Observables by taking one value from each
Observable and then emitting them as an array. It waits until each of the
source Observables has emitted at least one value before emitting a combined
result.
Use case: Use zip when you need to combine the latest
values from multiple Observables, but only when each has emitted at least one
value.
Example:
import { zip, of } from 'rxjs';
const observable1 = of('A', 'B', 'C');
const observable2 = of(1, 2, 3);
zip(observable1, observable2).subscribe(([val1, val2]) =>
{
console.log(val1, val2); // ['A', 1], ['B', 2],
['C', 3]
});
114. What is takeUntil in RxJS, and when should it be
used?
The takeUntil operator emits values from the source Observable until a notifier
Observable emits its first value. After that, it completes the source
Observable.
Use case: Use takeUntil when you want to unsubscribe
from an Observable based on an event or condition from another Observable, such
as stopping a stream when a user logs out or when a certain time elapses.
Example:
import { takeUntil, timer } from 'rxjs';
const stopNotifier$ = timer(5000); // Emits after 5 seconds
this.source$.pipe(
takeUntil(stopNotifier$) // Stop emitting from
source$ after 5 seconds
).subscribe(value => {
console.log(value); // Will stop after 5 seconds
});
115. What is auditTime in RxJS, and how is it different
from throttleTime?
- auditTime:
Emits the most recent value from the source Observable after a specified
time interval, but only emits once during each interval regardless of the
number of emitted values.
- throttleTime:
Emits the first value from the source Observable and then ignores
subsequent emissions for the specified duration, effectively
"throttling" the flow.
Use case: Use auditTime when you want to "take a
snapshot" of the source Observable periodically, but don't care about
intermediate emissions during that time.
Example:
import { auditTime } from 'rxjs';
this.source$.pipe(
auditTime(1000) // Emit the most recent value
once every 1 second
).subscribe(value => {
console.log(value); // Latest value every 1
second
});
116. What is concatMap in RxJS, and how does it differ
from mergeMap?
- concatMap:
It projects each value from the source Observable into an inner Observable
and subscribes to them sequentially. It waits for each inner Observable to
complete before subscribing to the next one.
- mergeMap:
It projects each value from the source Observable into an inner Observable
and subscribes to them concurrently, without waiting for each inner
Observable to complete.
Use case: Use concatMap when you need to process
inner Observables sequentially. Use mergeMap when you need to handle multiple
inner Observables concurrently.
Example with concatMap:
import { concatMap, of } from 'rxjs';
this.source$.pipe(
concatMap(value =>
of(value).pipe(delay(1000))) // Process values sequentially
).subscribe(value => {
console.log(value); // Processed one at a time
});
117. What is debounce in RxJS and how does it differ from
debounceTime?
- debounceTime:
It waits for a specific time of inactivity (no emissions) before emitting
the most recent value.
- debounce:
It waits for a custom Observable to emit a value before emitting the most
recent source value. The delay is based on a dynamic Observable rather
than a fixed time.
Use case: Use debounce when you need to apply a
custom debounce logic that depends on an external factor or condition, instead
of just waiting for a fixed delay.
Example:
import { debounce, timer } from 'rxjs';
this.source$.pipe(
debounce(() => timer(500)) // Wait for 500ms
after the last emission before emitting
).subscribe(value => {
console.log(value); // Latest value after custom
debounce
});
118. What is distinctUntilChanged in RxJS?
The distinctUntilChanged operator ensures that only distinct consecutive values
are emitted from the source Observable. If the value is the same as the
previous emission, it will not emit again.
Use case: Use distinctUntilChanged when you want to
skip emitting values that are the same as the previous one, such as in user
input scenarios where you only want to process changes.
Example:
import { distinctUntilChanged } from 'rxjs';
this.source$.pipe(
distinctUntilChanged() // Only emit if the
current value is different from the previous one
).subscribe(value => {
console.log(value); // Only distinct consecutive
values will be logged
});
119. What is repeatWhen in RxJS, and when would you use
it?
The repeatWhen operator allows you to specify a condition under which an
Observable will repeat itself. It takes a function that returns an Observable,
and once that Observable emits a value, the source Observable will resubscribe
and start emitting again.
Use case: Use repeatWhen when you want to restart an
Observable stream based on a custom condition, such as retrying an operation
after a delay or conditionally repeating the stream.
Example:
import { repeatWhen, delay } from 'rxjs';
this.source$.pipe(
repeatWhen(notifications =>
notifications.pipe(delay(1000))) // Resubscribe after 1 second delay
).subscribe(value => {
console.log(value); // The stream will repeat
after each notification
});
120. What is fromEvent in RxJS, and how is it useful?
The fromEvent operator creates an Observable from DOM events or any event-based
APIs. It listens for events like clicks, mouse movements, keypresses, etc., and
emits those events as values in the stream.
Use case: Use fromEvent when you need to listen to
user interactions (like button clicks) or other event-driven sources.
Example:
import { fromEvent } from 'rxjs';
const button = document.getElementById('myButton');
fromEvent(button, 'click').subscribe(event => {
console.log('Button clicked!', event);
});
121. What is mergeMap in RxJS, and how does it differ
from switchMap?
- mergeMap:
It subscribes to each inner Observable concurrently and emits values from
all of them as they arrive, regardless of order.
- switchMap:
It switches to the latest inner Observable and cancels any previous ones.
It emits values only from the latest inner Observable.
Use case: Use mergeMap when you need to handle
concurrent inner Observables. Use switchMap when you need to discard the result
of a previous Observable when a new one is emitted (e.g., search-as-you-type).
Example with mergeMap:
import { mergeMap } from 'rxjs';
this.source$.pipe(
mergeMap(value =>
this.http.get(`https://api.example.com/${value}`))
).subscribe(response => {
console.log(response); // Response from each API
call
});
122. What is repeat in RxJS?
The repeat operator causes the source Observable to resubscribe and restart the
emission of values a specified number of times. After the specified number of
repetitions, the Observable will complete.
Use case: Use repeat when you want to repeat the
source stream a certain number of times, useful in scenarios where you want to
retry an operation a few times before stopping.
Example:
import { repeat } from 'rxjs';
this.source$.pipe(
repeat(3) // Repeat the source stream 3 times
).subscribe(value => {
console.log(value); // Repeats the values 3
times
});
123. What is finalize in RxJS, and when is it triggered?
The finalize operator is used to perform cleanup logic, such as stopping
loading spinners or releasing resources, when an Observable completes or errors
out. It is executed when the Observable terminates, regardless of whether it
completes or errors.
Use case: Use finalize for performing any cleanup
tasks, like logging out, stopping a loading spinner, or resetting application
state.
Example:
import { finalize } from 'rxjs';
this.source$.pipe(
finalize(() => console.log('Cleanup after
stream is completed or errored'))
).subscribe({
next: value => console.log(value),
error: err => console.error(err)
});
124. What is share in RxJS?
The share operator is a multicast operator that makes the source Observable
shared among multiple subscribers. It essentially creates a "hot"
Observable, meaning that multiple subscribers will share the same underlying
stream, and the Observable will not be re-executed for each subscription.
Use case: Use share when you want to ensure that
multiple subscribers are receiving the same data without creating separate
executions of the Observable.
Example:
import { of, share } from 'rxjs';
const source$ = of('A', 'B', 'C').pipe(share());
source$.subscribe(value => console.log('Subscriber 1:',
value));
source$.subscribe(value => console.log('Subscriber 2:',
value));
Both subscribers will share the same source without
re-running the logic.
125. What is take in RxJS, and how does it work?
The take operator limits the number of emissions from the source Observable. It
will take only a specified number of values from the source Observable and then
automatically complete the stream.
Use case: Use take when you want to limit the number
of emitted values or process just the first few emissions.
Example:
import { take } from 'rxjs';
this.source$.pipe(
take(3) // Take only the first 3 values and then
complete
).subscribe(value => {
console.log(value); // Only the first 3 values
will be emitted
});
126. What is catchError in RxJS, and how do you handle
errors with it?
The catchError operator is used for handling errors in an Observable stream. It
allows you to catch and recover from errors by returning a new Observable or a
fallback value when an error occurs.
Use case: Use catchError when you want to handle
errors within your stream, either by providing an alternative stream or a
fallback value.
Example:
import { catchError, of } from 'rxjs';
this.source$.pipe(
catchError(error => {
console.error('Error:', error);
return of('Fallback value'); //
Return a fallback value on error
})
).subscribe(value => {
console.log(value); // 'Fallback value' if an
error occurs
});
127. What is exhaustMap in RxJS, and when would you use
it?
The exhaustMap operator projects each value from the source Observable into an
inner Observable. However, if a new value arrives while the inner Observable is
still executing, it will ignore the new value and continue with the current
one. It "exhausts" the source Observable's values until the inner
Observable completes.
Use case: Use exhaustMap when you want to process
values one by one, ignoring new emissions while processing an ongoing operation
(e.g., form submissions or authentication).
Example:
import { exhaustMap } from 'rxjs';
this.source$.pipe(
exhaustMap(value => this.apiRequest(value))
// Ignore new values while the request is in progress
).subscribe(result => {
console.log(result);
});
128. What is mergeAll in RxJS?
The mergeAll operator is used when you have an Observable of Observables, and
you want to merge the emissions of each inner Observable into a single stream.
It subscribes to each inner Observable and emits their values concurrently.
Use case: Use mergeAll when you have multiple
Observables and you want to combine their emissions without waiting for one to
complete before subscribing to the next.
Example:
import { mergeAll } from 'rxjs';
this.source$.pipe(
mergeAll() // Merge multiple Observables emitted
by the source into a single stream
).subscribe(value => {
console.log(value); // Emitting values
concurrently from all inner Observables
});
129. What is skipWhile in RxJS?
The skipWhile operator skips emissions from the source Observable as long as
they satisfy a provided condition. Once a value does not satisfy the condition,
it begins emitting values from that point onward.
Use case: Use skipWhile when you want to discard
initial values that meet a condition, and start emitting only when a certain
condition is no longer met.
Example:
import { skipWhile } from 'rxjs';
this.source$.pipe(
skipWhile(value => value < 10) // Skip
values less than 10
).subscribe(value => {
console.log(value); // Emit only values greater
than or equal to 10
});
130. What is startWith in RxJS, and when should it be
used?
The startWith operator emits a specified initial value before any values from
the source Observable. This is useful for providing a default value or an
initial state before the source Observable emits any data.
Use case: Use startWith when you want to provide an
initial value, like setting an initial loading state or providing default data
before actual values arrive.
Example:
import { startWith } from 'rxjs';
this.source$.pipe(
startWith('Loading...') // Emit 'Loading...'
first before any other values
).subscribe(value => {
console.log(value); // 'Loading...' first, then
the source values
});
131. What is windowTime in RxJS, and how does it work?
The windowTime operator creates a new "window" (a separate
Observable) that emits values in time intervals, with the window resetting
after each specified time period. It allows you to group values within fixed
time windows.
Use case: Use windowTime when you want to group
emitted values within time windows for processing.
Example:
import { windowTime } from 'rxjs';
this.source$.pipe(
windowTime(1000) // Group values into windows of
1 second
).subscribe(window$ => {
window$.subscribe(value => {
console.log(value); // Values
emitted within the 1-second window
});
});
132. What is concat in RxJS?
The concat operator is used to concatenate multiple Observables together. It
subscribes to each Observable in sequence, waiting for one to complete before
subscribing to the next one. Each Observable is emitted one after the other, in
order.
Use case: Use concat when you want to handle multiple
Observables sequentially, ensuring that one completes before the next one
starts.
Example:
import { concat, of } from 'rxjs';
const source1$ = of('A', 'B');
const source2$ = of('C', 'D');
concat(source1$, source2$).subscribe(value => {
console.log(value); // 'A', 'B', 'C', 'D'
});
133. What is takeWhile in RxJS?
The takeWhile operator emits values from the source Observable as long as they
satisfy a specified condition. Once a value no longer satisfies the condition,
it will complete the Observable.
Use case: Use takeWhile when you want to continue
emitting values until a condition is no longer met, such as when processing
values until a certain threshold is reached.
Example:
import { takeWhile } from 'rxjs';
this.source$.pipe(
takeWhile(value => value < 10) // Take
values as long as they are less than 10
).subscribe(value => {
console.log(value); // Values less than 10 will
be emitted
});
134. What is pairwise in RxJS?
The pairwise operator collects pairs of consecutive values from the source
Observable and emits them as an array. It pairs each value with the value
emitted immediately before it.
Use case: Use pairwise when you need to compare
consecutive values from the source stream, such as calculating differences or
comparing states over time.
Example:
import { pairwise } from 'rxjs';
this.source$.pipe(
pairwise() // Emit pairs of consecutive values
as arrays
).subscribe(([prev, current]) => {
console.log('Previous:', prev, 'Current:',
current);
});
135. What is combineLatest in RxJS?
The combineLatest operator combines the latest emissions from multiple
Observables and emits them as an array. It waits until each source Observable
has emitted at least one value, then emits a combination of the latest values.
Use case: Use combineLatest when you need to combine
the latest values from multiple Observables, such as combining user input with
server data.
Example:
import { combineLatest, of } from 'rxjs';
const source1$ = of('A', 'B');
const source2$ = of(1, 2);
combineLatest([source1$, source2$]).subscribe(([val1, val2])
=> {
console.log(val1, val2); // 'B', 2 (latest
values from both Observables)
});
136. What is repeatWhen in RxJS?
The repeatWhen operator allows you to specify a condition that triggers the
repetition of an Observable. It will resubscribe to the source Observable based
on the emissions from the notifier Observable.
Use case: Use repeatWhen when you want to repeat an
Observable based on custom logic, such as retrying an HTTP request on failure
after a delay.
Example:
import { repeatWhen, delay } from 'rxjs';
this.source$.pipe(
repeatWhen(notifications =>
notifications.pipe(delay(1000))) // Repeat after 1 second delay
).subscribe(value => {
console.log(value); // Repeat the stream
});
137. What is concatMapTo in RxJS?
The concatMapTo operator is similar to concatMap, but instead of mapping each
value to an inner Observable, it maps each value to the same inner Observable.
It is useful when you want to transform each emission to a static Observable.
Use case: Use concatMapTo when you need to emit a
constant Observable for each emission from the source Observable, while
ensuring that each emission is processed sequentially.
Example:
import { concatMapTo, of } from 'rxjs';
this.source$.pipe(
concatMapTo(of('A', 'B', 'C')) // For every
emission from source$, emit 'A', 'B', 'C'
).subscribe(value => {
console.log(value); // 'A', 'B', 'C' for each
emission of source$
});
138. What is bufferCount in RxJS?
The bufferCount operator collects values from the source Observable in buffers
of a specified size. Once the buffer is full, it emits the collected values as
an array and resets the buffer.
Use case: Use bufferCount when you want to group
values into arrays, each containing a fixed number of values, for batch
processing or analysis.
Example:
import { bufferCount } from 'rxjs';
this.source$.pipe(
bufferCount(3) // Group the source values into
buffers of size 3
).subscribe(buffer => {
console.log(buffer); // [[1, 2, 3], [4, 5, 6],
...]
});
139. What is shareReplay in RxJS?
The shareReplay operator is used to multicast the source Observable and cache
its emitted values, allowing subsequent subscribers to immediately receive the
most recent emissions without re-executing the Observable. It
"replays" the last emitted values for new subscribers.
Use case: Use shareReplay when you want to share data
between multiple subscribers, but don't want to recompute the result or
re-fetch data from a server every time.
Example:
import { of, shareReplay } from 'rxjs';
const source$ = of('A', 'B', 'C').pipe(shareReplay(2)); //
Replay the last 2 values
source$.subscribe(value => console.log('Subscriber 1:',
value)); // A, B, C
source$.subscribe(value => console.log('Subscriber 2:',
value)); // B, C
140. What is windowCount in RxJS?
The windowCount operator divides the source Observable's emissions into
fixed-sized "windows" (chunks) of a specified count. It emits each
window as a new Observable.
Use case: Use windowCount when you want to process
groups of values in windows of fixed size and perform operations on each chunk.
Example:
import { windowCount, take } from 'rxjs';
this.source$.pipe(
windowCount(3), // Create windows of 3 emissions
take(2) // Take only 2 windows
).subscribe(window$ => {
window$.subscribe(value => {
console.log(value); // Values
grouped in windows of 3
});
});
141. What is audit in RxJS, and how does it differ from
auditTime?
- audit:
Similar to auditTime, but it uses a custom Observable (the auditor) to
define the window for emitting the most recent value.
- auditTime:
Uses a fixed time interval for determining when to emit the most recent
value.
Use case: Use audit when you want to define the
debounce interval dynamically via another Observable, such as using
user-defined conditions or events to trigger emissions.
Example with audit:
import { audit, timer } from 'rxjs';
this.source$.pipe(
audit(() => timer(1000)) // Only emit after 1
second of inactivity
).subscribe(value => {
console.log(value); // Latest value after the
defined period
});
142. What is takeLast in RxJS?
The takeLast operator emits the last specified number of values from the source
Observable before it completes. It allows you to grab values from the end of
the stream.
Use case: Use takeLast when you need to retrieve the
last few emitted values from the stream, such as when you only care about the
most recent results.
Example:
import { takeLast } from 'rxjs';
this.source$.pipe(
takeLast(2) // Take the last 2 values emitted by
the source
).subscribe(value => {
console.log(value); // The last two emitted
values
});
143. What is defaultIfEmpty in RxJS, and when is it used?
The defaultIfEmpty operator emits a specified value if the source Observable
completes without emitting any values. This can be useful when you want to
provide a fallback or default value in case the Observable stream ends without
any emissions.
Use case: Use defaultIfEmpty when you need to handle
cases where the Observable may not emit any values, and you want to ensure that
a default value is emitted instead.
Example:
import { defaultIfEmpty } from 'rxjs';
this.source$.pipe(
defaultIfEmpty('No data available') // Emit a
default value if no values are emitted
).subscribe(value => {
console.log(value); // 'No data available' if
the source is empty
});
144. What is sample in RxJS, and how is it used?
The sample operator emits the latest value from the source Observable at
regular intervals based on a "sampler" Observable. The
"sampler" Observable triggers the emission, but the value emitted by
the source is captured at that point.
Use case: Use sample when you want to periodically
sample the most recent value emitted by the source Observable, such as in user
interface animations or status updates.
Example:
import { sample, interval } from 'rxjs';
this.source$.pipe(
sample(interval(1000)) // Take the latest value
every 1 second
).subscribe(value => {
console.log(value); // Latest value from the
source every second
});
145. What is debounce vs debounceTime in RxJS?
- debounceTime:
Emits the most recent value from the source Observable after a fixed
delay. It waits for a specified amount of time to pass without new
emissions before emitting.
- debounce:
Similar to debounceTime, but it allows you to control the debounce period
with a custom Observable. This means the delay period can be dynamically
adjusted.
Use case: Use debounce when you want a custom
debounce strategy, and debounceTime when you just need a fixed time period for
debouncing.
Example with debounce:
import { debounce, timer } from 'rxjs';
this.source$.pipe(
debounce(() => timer(500)) // Wait for 500ms
of inactivity before emitting
).subscribe(value => {
console.log(value); // Emission after 500ms of
no activity
});
146. What is switchAll in RxJS?
The switchAll operator subscribes to the first inner Observable emitted by the
source Observable. Once the inner Observable completes, it switches to the next
one emitted by the source Observable. It cancels any previously active inner
Observables.
Use case: Use switchAll when you need to ensure that
only the latest emitted inner Observable is active, discarding previous ones.
Example:
import { switchAll } from 'rxjs';
this.source$.pipe(
switchAll() // Subscribe to the latest inner
Observable emitted by the source
).subscribe(value => {
console.log(value); // Only the latest inner
Observable is active
});
147. What is finalize in RxJS and when would you use it?
The finalize operator allows you to perform actions when the Observable
completes or errors out, regardless of whether it completes normally or throws
an error. It is typically used for cleanup operations.
Use case: Use finalize to trigger cleanup tasks, such
as hiding loading indicators or stopping timers, after the Observable stream
completes or fails.
Example:
import { finalize } from 'rxjs';
this.source$.pipe(
finalize(() => console.log('Stream completed
or errored'))
).subscribe({
next: value => console.log(value),
error: err => console.error(err)
});
148. What is publishReplay in RxJS, and how does it work?
The publishReplay operator is a combination of the shareReplay and publish
operators. It not only shares the Observable but also replays the last emitted
values to new subscribers. It’s useful when you want to ensure that new
subscribers receive the most recent values.
Use case: Use publishReplay when you want to cache
the emitted values and share the Observable among multiple subscribers,
ensuring they all get the most recent values.
Example:
import { publishReplay, refCount, of } from 'rxjs';
const source$ = of('A', 'B', 'C').pipe(publishReplay(2),
refCount()); // Replay the last 2 values
source$.subscribe(value => console.log('Subscriber 1:',
value)); // 'A', 'B', 'C'
source$.subscribe(value => console.log('Subscriber 2:',
value)); // 'B', 'C'
Comments
Post a Comment