Group 13: RxJS & Observables — Interview Quick Revision
1. What is RxJS?
RxJS (Reactive Extensions for JavaScript) is a library for handling asynchronous and event-based operations using Observables. Angular uses RxJS for HTTP requests, reactive forms, and event handling.
2. What is an Observable?
An Observable represents a stream of values emitted over time. It can emit multiple values, complete, or produce an error.
const numbers$ = of(1, 2, 3);
numbers$.subscribe(x => console.log(x));
3. Why does Angular HttpClient return Observables?
Angular HttpClient returns Observables to support asynchronous execution, cancellation, error handling, and RxJS operators. HTTP requests execute when subscribed to.
4. Observable vs Promise — what is the difference?
|
Observable |
Promise |
|---|---|
|
Can emit multiple values |
Resolves once |
|
Lazy execution |
Eager execution |
|
Supports operators |
Uses |
|
Supports cancellation via unsubscribe |
No built-in cancellation |
5. What is subscribe()?
subscribe() starts listening to an Observable and handles emitted values, errors, and completion. It returns a Subscription that can be unsubscribed.
this.http.get('/api/users').subscribe(data => console.log(data));
6. What are RxJS operators?
RxJS operators are functions used to transform, filter, combine, or handle Observable streams. Common operators include map, filter, switchMap, tap, and catchError.
of(1, 2, 3).pipe(map(x => x * 2)).subscribe(console.log);
7. What does map() do?
map() transforms each emitted value into another value. It is commonly used to modify API response data.
of(1, 2, 3).pipe(map(x => x * 10)).subscribe(console.log);
// Output: 10, 20, 30
8. What does filter() do?
filter() allows only values that satisfy a condition to pass through the Observable stream.
of(1, 2, 3, 4).pipe(filter(x => x > 2)).subscribe(console.log);
// Output: 3, 4
9. What does tap() do?
tap() performs side effects such as logging or debugging without modifying the emitted values.
of(1, 2).pipe(tap(x => console.log('Log:', x))).subscribe();
10. What does catchError() do?
catchError() handles errors in an Observable stream and returns a replacement Observable or rethrows the error. It is commonly used for HTTP error handling.
this.http.get('/api/users').pipe(
catchError(err => { console.error(err); return of([]); })
);
11. What does switchMap() do?
switchMap() switches to a new inner Observable and unsubscribes from the previous one when a new value arrives. It is useful for search autocomplete.
search$.pipe(switchMap(term => this.http.get(`/api/search?q=${term}`)));
12. What does mergeMap() do?
mergeMap() executes multiple inner Observables concurrently without cancelling previous operations. It is useful for independent API requests.
ids$.pipe(mergeMap(id => this.http.get(`/api/users/${id}`)));
13. What does concatMap() do?
concatMap() executes inner Observables sequentially, waiting for one to complete before starting the next. It is useful when API execution order matters.
ids$.pipe(concatMap(id => this.http.post('/api/process', { id })));
14. What does exhaustMap() do?
exhaustMap() ignores new source emissions while the current inner Observable is running. It is useful for preventing duplicate form submissions.
submit$.pipe(exhaustMap(data => this.http.post('/api/save', data)));
15. switchMap vs mergeMap — what is the difference?
|
|
|
|---|---|
|
Cancels previous inner subscription |
Keeps previous inner subscriptions |
|
Latest request takes priority |
Requests execute concurrently |
|
Best for search/autocomplete |
Best for independent API calls |
Key Point: Use switchMap for latest-only requests and mergeMap when all requests must be processed.
16. What is forkJoin()?
forkJoin() executes multiple Observables and emits their last values together after all complete. It is commonly used for parallel HTTP requests.
forkJoin({ users: this.http.get('/api/users'), roles: this.http.get('/api/roles') })
.subscribe(result => console.log(result));
17. What is combineLatest()?
combineLatest() combines the latest values from multiple Observables and emits whenever any source changes, after every source has emitted at least once.
combineLatest([of(10), of(20)]).subscribe(console.log);
// Output: [10, 20]
18. What is a Subject?
A Subject is a special Observable that can both emit values and be subscribed to. It supports multicasting, allowing multiple subscribers to receive the same emissions.
const subject = new Subject<number>();
subject.subscribe(console.log); subject.next(10);
19. What is a BehaviorSubject?
A BehaviorSubject is a Subject that requires an initial value and stores the latest emitted value. New subscribers immediately receive the current value.
const user$ = new BehaviorSubject<string>('Guest');
user$.next('Admin');
20. Subject vs BehaviorSubject — what is the difference?
|
Subject |
BehaviorSubject |
|---|---|
|
No initial value required |
Initial value required |
|
Does not replay previous values |
Replays latest value |
|
No current-value getter |
Supports |
|
Useful for events |
Useful for shared state |
21. What is AsyncPipe?
AsyncPipe automatically subscribes to an Observable or Promise and displays its latest value in the template. It also handles subscription cleanup automatically.
@if (users$ | async; as users) {
<p>{{ users.length }} users</p>
}
22. How do you prevent subscription memory leaks?
Use AsyncPipe, takeUntilDestroyed(), or manual unsubscribe() to clean up long-running subscriptions. Completed HttpClient requests generally do not require manual unsubscription.
this.service.getData().pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(data => console.log(data));
23. What is takeUntilDestroyed()?
takeUntilDestroyed() is an Angular RxJS interop operator that automatically completes a subscription when the component or service is destroyed.
private destroyRef = inject(DestroyRef);
this.data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe();
Important Interview Revision Points
|
Concept |
Key Point |
|---|---|
|
RxJS |
Reactive programming library |
|
Observable |
Asynchronous data stream |
|
|
Listen to Observable values |
|
|
Transform values |
|
|
Filter emitted values |
|
|
Logging and side effects |
|
|
Handle errors |
|
|
Latest inner Observable only |
|
|
Concurrent execution |
|
|
Sequential execution |
|
|
Ignore new emissions while busy |
|
|
Wait for all to complete |
|
|
Combine latest emitted values |
|
|
Multicast event stream |
|
|
Holds latest value |
|
|
Automatic subscription management |
|
|
Automatic cleanup on destruction |
Interview priority: Focus particularly on questions 2, 3, 4, 5, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, and 23.
For an Angular + ASP.NET Core Full Stack Developer interview, the most important practical scenarios are using switchMap() for API-based searching, forkJoin() for parallel API calls, catchError() for API failures, and takeUntilDestroyed() for subscription cleanup.