Most Important RxJS operators to handle errors in angular | 8 RxJS operators we can use to handle errors in Angular?

RxJS is a library that provides a set of operators for reactive programming in angular. It handles errors in a declarative way and this helps developers to write clean and robust code.

Errors are part of programming and normally in imperative programming we use try-catch and if-else statements to handle the errors, but we know using them can be risky, and using them in large projects can make it difficult to maintain the code.

RxJS operators

Error handling in reactive programming with RxJS pipeable operators allows us to use a declarative approach.

RxJS operators in angular can help in handling errors in a flexible way and can help to catch and handle errors in different situations in the observable chain.

Here is the list of common RxJS operators we can use for error handling in reactive programming. Also this post you can use this as Rxjs operators cheat sheet because these explanations are easy to understand and properly explained with coding examples.

Here is the resources that I personally recommend for learning RxJS with Angular.

We will explain each error-handling operator in detail.

  1. catchError()
  2. retry()
  3. retryWhen()
  4. finalize()
  5. throwIfEmpty()
  6. timeout()
  7. delay()
  8. delayWhen()

Let’s explain RxJS Operators step by step with an angular code examples.

1. catchError()

It is used to catch the error which occurs in the observable chain. suppose we are fetching data from the API and then some error occurs, now what catchError() will do, it will take the error as input and throw it and you can console it as well, you can also return a new observable using throwError() function, which can emit the error with a message.

import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

fetchDataFromApi().pipe(
  catchError(error => {
    console.error('Error fetching data from api:', error);
    return throwError('your customize message goes here');
  })
).subscribe(data => {
  // Here you can handle your api response data
});

2. retry()

The retry() operator can be used to retry the observable sequence a specified number of times in case of an error. Let’s just understand it with an example. I am trying to fetch data from the API and suddenly its server goes down for a few milliseconds so if you don’t use retry then it will show the error. So retry() gives chance to try again for the number of times we mention inside the operator.

Let me show with code example.

import { retry } from 'rxjs/operators';

fetchDataFromApi().pipe(
  retry(3)
).subscribe(data => {
  // Here you can handle your api response data
});

Now this function fetchDataFromApi() is fetching data from the server using API and retry(3) will retry this request 3 times if an error occurs.

3. retryWhen()

Now you understand retry() operator right. But what if the server waking up time took more time and retry(3) just finished in a few milliseconds or a second? So with retryWhen() you can define the condition of delay time and also the number of tries you want.

Check out the example code.

import { retryWhen, delay } from 'rxjs/operators';

fetchDataFromApi().pipe(
  retryWhen(errors => errors.pipe(delay(2000), take(3)))
).subscribe(data => {
  // Here you can handle your api response data
});

retryWhen() is not just for using the delay() operator, the above example is just for the API and server response issues that normally occur.

retry() allows us to retry the observable sequence based on certain conditions. This operator takes a function as an argument that returns an observable that emits a value to trigger a retry.

4. finalize()

The finalize() operator is used to perform a specific action when the RxJS observable completes, whether it completes successfully or with an error. This operator can be useful for cleaning up resources or logging information or you can log a message regardless of whether it succeeds or fails

import { finalize } from 'rxjs/operators';

fetchDataFromApi().pipe(
  finalize(() => console.log('Fetching data from server Request complete'))
).subscribe(data => {
  // Here you can handle your api response data
});

5. throwIfEmpty()

What if the observable completes without emitting any value, for example, you have called an API request and this API response is just empty, it has no value. How you will detect it? catchError() won’t throw an error if there is no error. So To check for empty values we use the throwIfEmpty() operator.

import { throwIfEmpty } from 'rxjs/operators';

fetchDataFromApi().pipe(
  throwIfEmpty(() => new Error('Response has no value, its empty.'))
).subscribe(data => {
  // Here you can handle your api response data
});

6. timeout()

Sometimes what happens is that the observable takes a lot of time to complete, like an API response, it can take up to 30 seconds or more depending on the API optimization or server response time.

Do you want that your app will be stuck and wait for some response to complete infinitely? No Right.

Well, then there should be a solution that can stop the request if it takes more time than the desired time.

timeout() is the operator which we can use to stop the request if the response from the API takes too much time or the observable takes too much time to complete. With the timeout() operator, we can define the time limit. 1000 is equal to the 1 second inside the timeout() operator.

import { timeout } from 'rxjs/operators';

fetchDataFromApi().pipe(
  timeout(2000)
).subscribe(data => {
  // Here you can handle your api response data
});

7. delay()

You already know a bit about delay() as we discussed in the above example when we explained the retryWhen() operator.

delay() operator basically helps to add some delay in the emission of values from the observable. With retryWhen() we were using it to add some delay for every next retry for API call.

Understand delay() with an array example. Here we have an array with some values and we are going through each value and consoling them. so in this case after emitting each value we are adding a delay of 2 seconds.

import { from } from 'rxjs';
import { delay } from 'rxjs/operators';

const numbers = from([10, 20, 30, 40, 50]);

const delayedEmission = numbers.pipe(
  delay(2000)
);

delayedEmission.subscribe(emitValue => console.log(emitValue));

This is how you can use delay() to delay any observable to complete or to take a time gap after every emission of observable values.

8. delayWhen()

delayWhen() operator delays the observable until some condition is fulfilled. If there is a network request which needs to complete and then we need some delay so delayWhen() is the operator we can use.

Let’s understand it with an example.

import { interval } from 'rxjs';
import { delayWhen } from 'rxjs/operators';

const emittingSource = interval(2000);

const delaySource = emittingSource.pipe(
  delayWhen(() => timer(5000))
);

delaySource.subscribe(value => console.log(value));

In the above example, we are emitting a value every two seconds using interval() operator. Now we are creating a new observable delaySource by using delayWhen() operator on emittingSource observable.

Now delaySource will emit a value after a gap of 5 seconds which we are creating using another RxJS operator timer().

So basically delayWhen() operator can be used in RxJS to delay the emission of values based on the completion of another observable.

To know more about RxJS operators you can checkout this official link RxJS operators

I hope you like this article, if I missed some other important operator, please let me know. I will update the article. Thank you for Reading 🙂

Also Please comment if you have any queries. Bye!

Checkout this React JS Learning Path Tutorials for learning react.

Related Posts

angular change detection techniques

Understanding Angular Change Detection for Beginners | Angular 17 Change Detection Methods

Understanding how the Angular change detection technique helps in the process of building dynamic and responsive web applications. In this article, we’ll explore some essential concepts of…

TypeScript Strategies for Angular, Explaining Best Practices and Techniques

Angular has fully embraced TypeScript as its primary development language, a decision that has evolved into a widely accepted standard practice. TypeScript introduces robust features for static…

Unlocking the Future of Web Development: A Deep Dive into Angular 17 Features

Angular 17, the powerhouse in the realm of JavaScript frameworks, celebrated its 13th anniversary recently. From its inception with AngularJS, the framework has continuously evolved to meet…

angular-icon

How to use ngx-spinner in Angular to create a loading spinner for smoother user interactions

In this article, we will create a loading spinner component with ngx-spinner in angular application. ngx-spinner in angular provides a loading spinner component that we can use…

angular-icon

Master AngularFire2 and Angular by building a CRUD operation app

In this article, we are creating a CRUD application with angularFire2 and angular, This module basically provides direct access to the Firebase database, and by using angular…

angular-icon

Master Angular NgRx by creating a To-Do Application

In this article we are building a todo application using Angular NgRx, NgRx is used for state management in angular applications. Let’s start by creating a new…

This Post Has 3 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *