Angular RxJS Interview Questions

By Arvind Rai, February 18, 2024

Q.1 : Explain RxJS Observable.

Ans : Observable pushes the data lazily from producer to consumer. It is a collection of multiple values. Data transfer takes place in push and pull mode. In pull mode, producer does not know when data is fetched by consumer because data is pulled by consumer. In push mode, consumer does not know when data will be pushed by producer. JavaScript functions work on pull mode. RxJS Observable works on push mode. Observable starts emitting data once it is subscribed. In Angular, Observable can be subscribed using RxJS subscribe or async pipe.
In Angular HttpClient, HTTP methods return Observable instance.
@Injectable({
    providedIn: 'root'
})
export class UserService {
    constructor(private http: HttpClient) { }
    findUserById(id: number): Observable<User> {
        return this.http.get<User>("/api/user", {
            params: new HttpParams().set('id', id)
        });
    }
} 
Import Observable from ‘rxjs’.
import { Observable, of, pipe, throwError } from 'rxjs'; 

Q.2 : How will you subscribe Observable instance?

Ans : To subscribe Observable, use RxJS subscribe.
result$ = userService.findUserById(101);
result$.subscribe({
   next(v) {
      console.log("Value: ", v);
   },
   error(e) {
      console.error('Error occurred: ' + e);
   },
   complete() {
      console.log('Request completed.');
   }
}); 
Observable instance can also be subscribed using Angular async pipe in HTML template.
{{result$ | async}} 

Q.3 : What are RxJS operators?

Ans : RxJS operators are functions that are of two types.
1. Pipeable Operators : Operators that can be used with Observable.pipe() such as map, switchMap, mergeMap, concatMap, takeUntil, retry, catchError, throwError etc. Pipeable operators takes an observable as input and returns another observable.
Import pipeable operator from 'rxjs/operators' .
import { map, switchMap, debounceTime, catchError } from 'rxjs/operators'; 
2. Creation Operators : Operators that can be called as standalone functions to create observables such as of, from, interval, fromEvent, generate, range etc.
Import creation operator from 'rxjs' .
import { of, from, interval, fromEvent } from 'rxjs'; 

Q.4 : What is Observable.pipe() and how to use it?

Ans : pipe function takes pipeable operators as arguments. We can pass as many pipeable operators as we want. It passes the source observable to first operator and result of that operator is passed to another operator and so on.
of(101, 102).pipe(
   delay(1000),
   map(num => num * 2)
).subscribe(v => console.log(v)); 
Output 202, 204.

Q.5 : What is difference between RxJS of and from?

Ans : of : Converts the specified arguments into an observable sequence.
of("a", "b", "c").subscribe(e => console.log(e)); 
from : Converts the specified array into an observable.
from(["a", "b", "c"]).subscribe(e => console.log(e)); 

Q.6 : Explain RxJS map operator.

Ans : map applies the given function to each item emitted by source.
of(1, 2, 3, 4).pipe(map(e => e * e))
   .subscribe(output => console.log(output)); 
Output is 1, 4, 9, 16.

Q.7 : Explain RxJS switchMap operator.

Ans : switchMap applies each element of source to a specified function that returns an observable called as inner observables. switchMap always emits data only by latest inner observable. Suppose and inner observable is emitting data and mean while another inner observable is created then old one will stop and new one will emit data.
of(10, 20, 30).pipe(
   switchMap(e =>
      of(2).pipe(
        delay(1000),
        map(v => v * e)
      )
)).subscribe(output => console.log(output)); 
Output is 60.
switchMap is useful in responding search results. If we keep on changing keywords in search, we will get response only for latest keyword.

Q.8 : Explain RxJS mergeMap operator.

Ans : mergeMap applies a given function to each source element and returns an observable as inner observable. At last all inner observables are merged.
of("a", "b", "c").pipe(
   mergeMap(e =>
      of("@").pipe(
        map(v => v + e)
      )
)).subscribe(output => console.log(output)); 
Output @a, @b and @c

Q.9 : Explain RxJS concatMap operator.

Ans : concatMap creates inner observable for every source items and waits to complete them. Later all output of inner observables are merged in their order they are processed.
of("Mohit", "Nilesh").pipe(
   concatMap(se => of("Shree").pipe(
      delay(2000),
      map(e => e + " " + se)
   ))
).subscribe(res => console.log(res)); 
Find the output.
(after 2 seconds)
Shree Mohit
(after 2 seconds)
Shree Nilesh 
For the first source item "Mohit", inner observable is created that will emit data after 2 seconds. For the second item "Nilesh", inner observable is created that will emit data after 2 seconds since the time first inner observable has emitted.


Q.10 : Explain RxJS exhaustMap operator.

Ans : exhaustMap applies a given function to each item of source that returns an observable as inner observable and allows to emit only old inner observable if before its completion a new inner observable is created. exhaustMap behaviour is opposite of switchMap operator. Look into the below code snippet of exhaustMap.
of(100, 200, 300).pipe(
   exhaustMap(e =>
      of(2).pipe(
        delay(1000),
        map(v => v * e)
      )
)).subscribe(output => console.log(output)); 
Output is 200.

Q.11 : How will you handle errors on observable using RxJS throwError?

Ans : throwError creates an error instance and emits it at once on subscribe.
of("A", "B", "C").pipe(
   map(se => {
      if (se === "B") {
         return throwError(() => "Error occurred for " + se);
      }
      return se;
   })
).subscribe({
   next(v) {
      console.log(v);
   },
   error(e) {
      console.error(e);
   }
}); 
Output will be A then error message then C.

Q.12 : How will you handle errors on observable using RxJS catchError?

Ans : catchError catches the error on observable and returns another observable by handling the error or can throw another error.
of("A", "B", "C").pipe(
   map(se => {
      if (se === "B") {
         throw new Error("Error occurred for " + se);
      }
      return se;
   }),
   catchError(err => {
      console.error(err.message);
      return of("Z");
   })
).subscribe({
   next(v) {
      console.log(v);
   },
   error(e) {
      console.error(e);
   }
}); 
Output will be A and Z.

Q.13 : Explain RxJS retry operator.

Ans : retry operator resubscribes the source observable in case source observable calls error. We need to pass number of retry attempt to retry operator such as retry(3) and this will resubscribe source up to maximum 3 times. If no number is passed, retry() will attempt for infinite time if error call continues on source observable.
of("A").pipe(
   mergeMap(data => {
      console.log(data);
      if (data === "A") {
         return throwError(() => 'Error Occurred.');
      }
      return of(data);
   }),
   retry(3)
).subscribe({
   next(v) {
      console.log(v);
   },
   error(e) {
      console.error(e);
   }
}); 
Output A, A, A, A then Error Occurred.

Q.14 : Explain RxJS filter operator.

Ans : filter operator filters the emitted values by source. It allows to emit only those values that satisfies the specified predicate.
of(1, 2, 3, 4, 5, 6, 7).pipe(
   filter(num => num % 2 === 0)
).subscribe(v => console.log(v)); 
Output is 2, 4, 6.

Q.15 : Explain RxJS tap operator.

Ans : tap is used to perform side-effects on source items such as logging. tap returns the same observable obtained from source.
of(1, 2, 3, 4, 5, 6, 7).pipe(
   tap(s => console.log("Before Filter: " + s)),
   filter(num => num % 2 === 1),
   tap(s => console.log("After Filter: " + s))  
).subscribe(v => console.log(v)); 



Q.16 : Explain RxJS takeUntil operator.

Ans : RxJS takeUntil operator allows source observable to emit until another observable specified to it starts to emit.
interval(500).pipe(
   takeUntil(timer(2000))
).subscribe(e => console.log(e)); 
Output will be 0 1 2 3 4
interval(500) is emitting data after every 500 ms. Once timer(2000) will emit after 2000 ms. For these two 2000 ms, source observable interval(500) will emit data as 0 1 2 3 4.

Q.17 : Explain RxJS takeWhile operator.

Ans : takeWhile works same as takeUntil but the difference is takeWhile accepts an observable whereas takeWhile accepts a predicate. takeWhile allows source observable to emit until predicate returns false.
of(1, 2, 3, 4).pipe(
   takeWhile((v, i) => v < 3)
).subscribe(e => console.log(e)); 
Output is 1 and 2.
v and i is value and index of source observable emission. Each item will be checked by predicate, if predicate returns true then that item is passed. Once predicate returns false source observable stops emitting and completes itself.

Q.18 : Explain RxJS takeLast operator.

Ans : takeLast emits last N number of items emitted by source after completion. Here N is the number specified to it.
of("A", "B", "C", "D").pipe(
   takeLast(2)
).subscribe(item => console.log(item)); 
Output is "C" and "D".
takeLast(2) will emit last two items after source has emitted all its items.

Q.19 : Explain RxJS take operator.

Ans : take emits first N number of items from source observable and then completes.
of("A", "B", "C", "D").pipe(
   take(2)
).subscribe(item => console.log(item)); 
Output is "A" and "B".
take(2) allows source to emit first two numbers and then completes.

Q.20 : Explain RxJS max and min operators.

Ans : max and min emit item with maximum and minimum values respectively for the given comparer function. If comparer is not specified, they emit max and min with natural order. In case of number they emit max or min number and in case of alphabet they emit max or min in alphabetic order.
Find an example with comparer function.
Using max :
const itemWeights = [
   { name: "ABC", weight: 10 },
   { name: "PQR", weight: 15 },
   { name: "XYZ", weight: 5 }
];

from(itemWeights).pipe(
   max((item1, item2) => item1.weight < item2.weight ? -1 : 1)
).subscribe(item => console.log(item)); 
Output
{ name: "PQR", weight: 15 } 
Using min :
from(itemWeights).pipe(
   min((item1, item2) => item1.weight < item2.weight ? -1 : 1)
).subscribe(item => console.log(item)); 
Output
{ name: "XYZ", weight: 5 } 

Q.21 : Explain RxJS count operator.

Ans : count operator counts the number of items emitted by source and count is emitted once source observable emission is complete.
of("P", "Q", "R", "S").pipe(
  count()
).subscribe(num => console.log(num)); 
Output is 4.

Q.22 : Explain RxJS delayWhen operator.

Ans : delayWhen delays the source observable emission by the given delay duration selector observable that emits a time to delay.
of("A", "B").pipe(
   delayWhen((item, index) => {
   	  console.log(item + "-" + index);
      return timer(2000);
   })
).subscribe(e => console.log(e)); 
We will get output after 2 seconds delay. Delay duration selector in delayWhen has two arguments, first is item and second is index of that item. We can use these arguments to set delay time for each items separately.

Q.23 : Explain RxJS delay operator.

Ans : delay delay source emission by the given due time as number or date. We can pass time in milliseconds and once that time is passed then emission starts. If we pass date then once that date is passed then emission starts.
of(101, 102).pipe(
   delay(3000)
).subscribe(e => console.log(e)); 
Data will emit after 3 seconds.
The difference in delay and delayWhen is in their arguments. The delay accepts a number or date to delay whereas delayWhen accepts a function that returns an observable that emits time to delay.

Q.24 : Explain RxJS debounce operator.

Ans : debounce emits only latest item emitted by source after the delay time emitted by another observable.
of ("X", "Y", "Z").pipe(
   debounce(v=> interval(1000))
).subscribe(v => console.log(v)); 
Output will be Z.
interval(1000) will emit after one second. Each item of source will be discarded by debounce if duration time is not over. In our case, source will emit with no delay and hence all item will reach to debounce one-by-one and every will be discarded if new item reaches. In this way Z will reach at last and hence after 1 second, Z will be emitted.

Q.25 : Explain RxJS debounceTime operator.

Ans : debounceTime emits a source item only after the specified time has passed without another source emisssion.
of ("A", "B", "C").pipe(
   debounceTime(1000)
).subscribe(v => console.log(v)); 
Output is C.

Q.26 : Explain RxJS combineLatestWith operator.

Ans : combineLatestWith combines latest values from source and all inner observables into array.
TS
result$: any;
ngOnInit() {
   this.result$ = of("X", "Y").pipe(
      combineLatestWith(of("101")),
      combineLatestWith(of("102"))
   );
} 
HTML
{{result$ | async}} 
Output : Y, 101, 102

Q.27 : Explain RxJS fromEvent operator.

Ans : fromEvent creates an observable that emits specified event by specified target.
Suppose we want to emit click event by clicking on a button, we will write code in Angular as below.
@Component({
   selector: 'click-app',
   standalone: true,
   template: '<button #click>Click Me!</button>'
})
export class ClickComponent implements AfterViewInit {
   @ViewChild('click') clickMe!: ElementRef;
   ngAfterViewInit() {
      const clicks$ = fromEvent(this.clickMe.nativeElement, 'click');
      clicks$.subscribe(click => console.log(click));
   }
} 

References

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us