Rxjs throw error

RxJS throwError operator is used to create an Observable that emits an error notification immediately and no element. throwError can be used composing with other Observable, such as in a mergeMap, switchMap etc.

February 18, 2019

RxJS throwError operator is used to create an Observable that emits an error notification immediately and no element. throwError can be used composing with other Observable, such as in a mergeMap, switchMap etc. throwError is introduced in RxJS 6 and we need to use it in place of Observable.throw(). Angular 6 has integrated RxJS 6 and Angular 6 onwards we can use throwError that will return Observable instance with error message. We catch error using catchError returned by throwError.

throwError is imported as following.

import { throwError } from 'rxjs'; 

Here on this page we will discuss using RxJS throwError with examples step by step.

Contents
  • Technologies Used
  • Using throwError
  • throwError, retry and catchError
  • JavaScript throw vs RxJS throwError
  • Complete Example
  • Run Application
  • References
  • Download Source Code

Technologies Used

Find the technologies being used in our example.

1. Angular 7.0.0

2. Angular CLI 7.0.3

3. TypeScript 3.1.1

4. Node.js 10.3.0

5. NPM 6.1.0

6. RxJS 6.3.3

7. In-Memory Web API 0.6.1

Using throwError

Let us understand how to use throwError operator.

Example-1:
In this example, the Observable instance will emit 1,2,3,4 but for the number 3, we will throw error.

  of(1,2,3,4).pipe(
	mergeMap(data => {
	  if (data === 3) {
		return throwError('Error Occurred for data: '+ 3);
	  }
	  return of(data);
	})
  ).subscribe(res => console.log(res),
	 err => console.error(err)
  ); 

Output will be

1 2
Error Occurred for data: 3 

Example-2:
Here we will emit numbers after every 2 seconds and for number 2, an error is thrown.

  interval(2000).pipe(
	mergeMap(x => x === 2
	  ? throwError('Error: Received 2')
	  : of('a', 'b')
	),
  ).subscribe(x => console.log(x),
	e => console.error(e)
  ); 

Find the output.

a b a b 
Error: Received 2 

throwError, retry and catchError

Here we will create an example with throwError, retry and catchError.

of("A", "B").pipe(
  switchMap(el => {
	if (el === "B") {
	 return throwError("Error occurred.");
	}
	return el;
  }),
  retry(2),
  catchError(err => {
	console.error(err);
	return throwError("User defined error.");
  })
).subscribe(el => console.log(el),
	err => console.error(err),
	() => console.log("Processing Complete.")
); 

Find the output.

A A A
Error occurred.
User defined error. 

When the source Observable emits element B, error is thrown by throwError. The operator retry resubscribes 2 times and finally error is caught by catchError operator and then we again throw user defined error using throwError. Process complete block will not execute because error occurs.

JavaScript throw vs RxJS throwError

JavaScript throw statement throws user-defined exception. throw does not return Observable instance. Find the sample code snippet for throw.

switchMap(el => {
  if (el === "B") {
    throw new Error("Error occurred.");
  }
  return el;
}) 

RxJS throwError() returns Observable instance that emits only error and no element. Find the sample code for throwError().

switchMap(el => {
  if (el === "B") {
    return throwError("Error occurred.");
  }
  return el;
}) 

Complete Example

book.component.ts

import { Component, OnInit } from '@angular/core';
import { of, throwError, interval } from 'rxjs';
import { switchMap, debounceTime, catchError, retry, mergeMap } from 'rxjs/operators';

import { BookService } from './book.service';
import { Book } from './book';
import { FormControl, FormBuilder, FormGroup } from '@angular/forms';

@Component({
   selector: 'app-book',
   template: `
    <h3>Search Book</h3>
    <form [formGroup]="bookForm">
      ID: <input formControlName="bookId">
    </form>
    <br/>
    <div *ngIf="book">
      Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}
    </div>
   `
})
export class BookComponent implements OnInit { 
   book: Book;
   constructor(private bookService: BookService, private formBuilder: FormBuilder) { }
   ngOnInit() {
      of(1,2,3,4).pipe(
        mergeMap(data => {
          if (data === 3) {
            return throwError('Error Occurred for data: '+ 3);
          }
          return of(data);
        })
      ).subscribe(res => console.log(res),
         err => console.error(err)
      );

      interval(2000).pipe(
        mergeMap(x => x === 2
          ? throwError('Error: Received 2')
          : of('a', 'b')
        ),
      ).subscribe(x => console.log(x),
         e => console.error(e)
      );

      //-------------------------
      this.retryAndHandleError();
      this.searchBook();
   }

   retryAndHandleError() {
    of("A", "B").pipe(
      switchMap(el => {
        if (el === "B") {
         return throwError("Error occurred.");
        }
        return el;
      }),
      retry(2),
      catchError(err => {
        console.error(err);
        return throwError("User defined error.");
      })
    ).subscribe(el => console.log(el),
        err => console.error(err),
        () => console.log("Processing Complete.")
    );
   }

   bookId = new FormControl(); 
   bookForm: FormGroup = this.formBuilder.group({
      bookId: this.bookId
     }
   );
   searchBook() {
    this.bookId.valueChanges.pipe(
      debounceTime(1000),
      switchMap(id => {
        return this.bookService.getBook(id);
      }),
      catchError(err => {
        return throwError('User defined error.');
      })
    ).subscribe(res => this.book = res,
        err => {
          console.error(err);
          this.book = null;
          this.searchBook();
        }
    ) 
  }
} 

book.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Book } from './book';

@Injectable({
    providedIn: 'root'
})
export class BookService {
    bookUrl = "/api/books";	
    constructor(private http: HttpClient) { }
    getBook(id: number): Observable<Book> {
      let url = this.bookUrl + "/" + id;   
      return this.http.get<Book>(url);
    }  
} 

book.ts

export interface Book {
   id: number;
   name: string;
   category: string;
} 

app.component.ts

import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
    <app-book></app-book>
   `
})
export class AppComponent { 
} 

test-data.ts

import { InMemoryDbService } from 'angular-in-memory-web-api';

export class TestData implements InMemoryDbService {
  createDb() {
    let bookDetails = [
      { id: 101, name: 'Angular by Krishna', category: 'Angular' },
      { id: 102, name: 'Core Java by Vishnu', category: 'Java' },
      { id: 103, name: 'NgRx by Rama', category: 'Angular' }
    ];
    return { books: bookDetails };
  }
} 

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent }  from './app.component';
import { BookComponent }  from './book.component';

//For InMemory testing
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { TestData } from './test-data';

@NgModule({
  imports: [     
      BrowserModule,
      HttpClientModule,
      FormsModule,
      ReactiveFormsModule,
      InMemoryWebApiModule.forRoot(TestData)		
  ],
  declarations: [
      AppComponent,
      BookComponent
  ],
  providers: [
  ],
  bootstrap: [
      AppComponent
  ]
})
export class AppModule { } 

Run Application

To run the application, find the steps.

1. Download source code using download link given below on this page.

2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.

3. Install angular-in-memory-web-api@0.6.1

4. Run ng serve using command prompt.

5. Access the URL http://localhost:4200

We can see output in console as following.

Angular throwError

References

RxJS throwError

Angular RxJS retry

Angular catchError

Download Source Code

POSTED BY

ARVIND RAI

Angular ThrowError operator returns an observable, which on subscription immediately errors out. It does not emit any results.

Table of Contents

  • ThrowError
  • Throw Error Vs ThrowError
    • Throw Error Example
    • ThrowError
  • Using ThrowError
    • Using with catchError
    • Using it with MergeMap
  • References

ThrowError creates a new observable. Hence we must subscribe to it. The following example creates an ThrowError observable and then subscribes to it.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

import { Component, VERSION } from «@angular/core»;

import { Observable, of, from, throwError } from «rxjs»;

import { map, catchError } from «rxjs/operators»;

@Component({

  selector: «my-app»,

  templateUrl: «./app.component.html»,

  styleUrls: [«./app.component.css»]

})

export class AppComponent {

  name = «Angular « + VERSION.major;

  obs = throwError(«Error From ThrowError observable»);

  ngOnInit() {

    this.obs.subscribe(

      el => {

        console.log(«Value Received :» + el);

      },

      err => {

        console.log(«Error caught at Subscriber :» + err);

      },

      () => console.log(«Processing Complete»)

    );

  }

}

****Console Window

Error caught at Subscriber: Error From ThrowError observable

Source Code

First, we create an observable using throwError. The first argument to the throwError is the error object. This error object is passed to the consumers when it raises the error notification.

obs = throwError(«Error From ThrowError observable»)

We, subscribe to it in the ngOnInit method.

The observable immediately raises the error notification and completes. The error callback is invoked and we will see the error message in the console window.

      err => {

        console.log(«Error caught at Subscriber :» + err);

      },

Throw Error Vs ThrowError

It is very easy confuse between the Throw Error With ThrowError.

Throw Error throws an error. It is a JavaScript construct and is not part of the RxJs. We need to use the try/catch block to catch the errors thrown from the Throw Error. The RxJS uses the try/catch block to catch any errors thrown from the observables. And when they catch one, they emit an error notification (raises the error callback), and then the observable stops.

ThrowError does not throw errors like throw Error. It returns a new observable, which emit an error notification (raises the error callback), and then stops.

Throw Error Example

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

import { Component, VERSION } from «@angular/core»;

import { Observable, of, from, throwError } from «rxjs»;

import { map, catchError } from «rxjs/operators»;

@Component({

  selector: «my-app»,

  templateUrl: «./app.component.html»,

  styleUrls: [«./app.component.css»]

})

export class AppComponent {

  srcArray = from([1, 2, «A», 4]);

  obs = this.srcArray.pipe(

    map(val => {

      let result = (val as number) * 2;

      if (Number.isNaN(result)) {

        console.log(«Error in the observable»);

        throw Error(«Not a Number»);

      }

      return result;

    })

  );

  ngOnInit() {

    this.obs.subscribe(

      el => {

        console.log(«Value Received :» + el);

      },

      err => {

        console.log(«Error caught at Subscriber :» + err);

      },

      () => console.log(«Processing Complete.»)

    );

  }

}

***Console ****

Value Received :2

Value Received :4

Error in the observable

Error caught at Subscriber :Error: Not a Number

Source Code

The observable emits values 2 & 4.

When map operators receive the value A it uses throw Error to throw an error. The observable catches this error and raises the error notification and terminates.

The last value 8 is never emitted.

ThrowError

Now, let us replace the throw Error with return throwError

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

import { Component, VERSION } from «@angular/core»;

import { Observable, of, from, throwError } from «rxjs»;

import { map, catchError } from «rxjs/operators»;

@Component({

  selector: «my-app»,

  templateUrl: «./app.component.html»,

  styleUrls: [«./app.component.css»]

})

export class AppComponent {

  name = «Angular « + VERSION.major;

  srcArray = from([1, 2, «A», 4]);

  obs = this.srcArray.pipe(

    map(val => {

      let result = (val as number) * 2;

      if (Number.isNaN(result)) {

        console.log(«Error in the observable»);

        return throwError(«Not a Number»);

      }

      return result;

    })

  );

  ngOnInit() {

    this.obs.subscribe(

      (el: any) => {

        console.log(«Value Received :» + el);

      },

      err => {

        console.log(«Error caught at Subscriber :» + err);

      },

      () => console.log(«Processing Complete.»)

    );

  }

}

****Console ********

Value Received :2

Value Received :4

Error in the observable

Value Received :[object Object]

Value Received :8

Processing Complete

Source Code

The observable emits values 2 & 4.

When the map operator receive the value A it returns throwError. Remember throwError returns an observable. It will raise the error notification, only if you subscribe to it.

The map operator does not subscribe to the observable. It just returns it to the subscriber.

Hence the subscriber receives the throwError observable as value. Hence you see [object Object] in the console.

Since there is no error raised, the observable continues and emits the next value 8 and then completes.

Using ThrowError

The throwError needs to be subscribed for it to emit error notification. We can use it to compose with other Observables such as mergeMap,  switchMap, catchError etc.

Using with catchError

The following example, shows how to use ThrowError with CatchError

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

import { Component, OnInit } from «@angular/core»;

import { throwError, from } from «rxjs»;

import { map, catchError } from «rxjs/operators»;

@Component({

  selector: «my-app»,

  templateUrl: «./app.component.html»,

  styleUrls: [«./app.component.css»]

})

export class AppComponent {

  srcArray = from([1, 2, «A», 4]);

  obs = this.srcArray.pipe(

    map(val => {

      let result = (val as number) * 2;

      if (Number.isNaN(result)) {

        console.log(«Errors Occurred in Stream»);

        throw new Error(«Result is NaN»);

      }

      return result;

    }),

    catchError(error => {

      console.log(«Caught in CatchError. Throwing error»);

      return throwError(error);

    })

  );

  ngOnInit() {

    this.obs.subscribe(

      el => {

        console.log(«Value Received « + el);

      },

      err => {

        console.log(«Error caught at Subscriber « + err);

      },

      () => console.log(«Processing Complete.»)

    );

  }

}

******* CONSOLE *******

Value Received 2

Value Received 4

Errors Occurred in Stream

Caught in CatchError. Throwing error

Error caught at Subscriber Error: Result is NaN

Source Code

The code throws the error using throw error in map operator.

CatchError will catch this error. We use the CatchError to handle the errors thrown by the Angular Observable. Once we handle the error, we must return an observable. We can either return a replacement observable or return an error. The observable returned from CatchError is immediately subscribed.

Hence we can use the throwError here, which is immediately subscribed , which in turn emits an error notification

    catchError(error => {

      console.log(«Caught in CatchError. Throwing error»);

      return throwError(error);

    })

Using it with MergeMap

The Angular MergeMap maps each value from the source observable into an inner observable, subscribes to it, and then starts emitting the values from it.

In the following example, we use throwError to return a observable, when we receive the value 3. The MergeMap subscribes to this new observable and raises the error notification and stops.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

import { Component, OnInit } from «@angular/core»;

import { throwError, of } from «rxjs»;

import { map, mergeMap, catchError } from «rxjs/operators»;

@Component({

  selector: «my-app»,

  templateUrl: «./app.component.html»,

  styleUrls: [«./app.component.css»]

})

export class AppComponent {

  srcObservable = of(1, 2, 3, 4);

  innerObservable = of(«A», «B»);

  obs = this.srcObservable.pipe(

    mergeMap(val => {

      console.log(«Source value « + val);

      console.log(«starting new observable»);

      if (val == 3) return throwError(«Error in observable»);

      return this.innerObservable;

    })

  );

  ngOnInit() {

    this.obs.subscribe(

      el => {

        console.log(«Value Received « + el);

      },

      err => {

        console.log(«Error caught at Subscriber « + err);

      },

      () => console.log(«Processing Complete.»)

    );

  }

}

***Console ****

Source value 1

starting new observable

Value Received A

Value Received B

Source value 2

starting new observable

Value Received A

Value Received B

Source value 3

starting new observable

Error caught at Subscriber Error in observable

Source Code

References

ThrowError API

Read More

Creates an observable that will create an error instance and push it to the consumer as an error immediately upon subscription.

Just errors and does nothing else

throw marble diagram

This creation function is useful for creating an observable that will create an error and error every time it is subscribed to. Generally, inside of most operators when you might want to return an errored observable, this is unnecessary. In most cases, such as in the inner return of concatMap, mergeMap, defer, and many others, you can simply throw the error, and RxJS will pick that up and notify the consumer of the error.

Example

Create a simple observable that will create a new error with a timestamp and log it and the message every time you subscribe to it

import { throwError } from 'rxjs';

let errorCount = 0;

const errorWithTimestamp$ = throwError(() => {
  const error: any = new Error(`This is error number ${ ++errorCount }`);
  error.timestamp = Date.now();
  return error;
});

errorWithTimestamp$.subscribe({
  error: err => console.log(err.timestamp, err.message)
});

errorWithTimestamp$.subscribe({
  error: err => console.log(err.timestamp, err.message)
});

Unnecessary usage

Using throwError inside of an operator or creation function with a callback, is usually not necessary

import { of, concatMap, timer, throwError } from 'rxjs';

const delays$ = of(1000, 2000, Infinity, 3000);

delays$.pipe(
  concatMap(ms => {
    if (ms < 10000) {
      return timer(ms);
    } else {
      
      return throwError(() => new Error(`Invalid time ${ ms }`));
    }
  })
)
.subscribe({
  next: console.log,
  error: console.error
});

You can just throw the error instead

import { of, concatMap, timer } from 'rxjs';

const delays$ = of(1000, 2000, Infinity, 3000);

delays$.pipe(
  concatMap(ms => {
    if (ms < 10000) {
      return timer(ms);
    } else {
      
      throw new Error(`Invalid time ${ ms }`);
    }
  })
)
.subscribe({
  next: console.log,
  error: console.error
});

Returns an observable that will error with the specified error immediately upon subscription.

Notifies the consumer of an error using a given scheduler by scheduling it at delay 0 upon subscription.

Понравилась статья? Поделить с друзьями:
  • Runtimeerror cuda error invalid device ordinal
  • Runtime error 2147319767 80028029 automation error
  • Runtime error 207 паскаль
  • Runtime error 207 pascal
  • Runtime error 203 at 0040a9cf