The simplest way for RxJS error handling is to provide an error callback when subscribing an Observable.
Error callback in subscribe
Ex:
of(1, 2, 3, 4)
.pipe(
map(
next => {
// Throw an error if the input value equals to 2
if (next === 2) {
throw new Error('My Error');
}
return next;
}
)
)
.subscribe(
value => console.log('Success: ' + value),
err => console.log('Handle the error: ' + err),
() => console.log('complete'),
);
Result:
Success: 1
Handle the error: Error: My ErrorAccording to the example above, we can handle errors simply in subscribe error callback, but this approach is very simple, and we cannot do much thing such as replacing the emitted value from errors or retrying it. Using catchError and retryWhen Operator, we can handle errors in Observable Stream, which make us have more controls.
Catch and Replace Approach
Using catchError, we can return a new Observable which emits a default value if there is an error out. Then, the error callback in subscribe will not be called..
Ex:
of(1, 2, 3, 4)
.pipe(
map(
next => {
// Throw an error if the input value equals to 2
if (next === 2) {
throw new Error('My Error');
}
return next;
}
),
// Return default value if it catches errors
catchError(err => of(0)),
)
.subscribe(
value => console.log('Success: ' + value),
err => console.log('Handle the error: ' + err),
() => console.log('complete'),
);
Result:
Success: 1
Success: 0
completeAccording to the result above, we can notice that the success and complete callback were triggered instead of error callback.
Catch and Rethrow Approach
We also can use catchError operator to catch the error and deal with it locally. And rethrow it to make this error be caught by error callback in subscribe.
Ex:
of(1, 2, 3, 4)
.pipe(
map(
next => {
// Throw an error if input value equals to 2
if (next === 2) {
throw new Error('My Error');
}
return next;
}
),
// Catch and deal with the error locally
// And rethrow this error
catchError(
err => {
console.log('Handle error in Observable Stream');
return throwError(err);
}
),
)
.subscribe(
value => console.log('Success: ' + value),
err => console.log('Handle the error: ' + err),
() => console.log('complete'),
);
Result:
Success: 1
Handle error in Observable Stream
Handle the error: Error: My Error
Retry
We can utilize retryWhen operator to re-subscribe the error-out Stream.
Ex:
of(1, 2, 3, 4)
.pipe(
map(
next => {
// Throw an error if input value equals to 2 (with half chance)
if (next === 2 && Math.random() > 0.5) {
throw new Error('My Error');
}
return next;
}
),
// Retry after 2 seconds if there is an error
retryWhen(
error => {
return error
.pipe(
delayWhen(() => timer(2000))
);
}
)
)
.subscribe(
value => console.log('Success: ' + value + ' in ' +
Date.now() / 1000),
err => console.log('Handle the error: ' + err),
() => console.log('complete'),
);
Result:
Success: 1 in 1636809816.598
Success: 1 in 1636809818.613
Success: 2 in 1636809818.614
Success: 3 in 1636809818.614
Success: 4 in 1636809818.614
complete
Catch and Continue
According to this stackoverflow article, we even can re-subscribe the source Observable.
Ex:
of(1, 2, 3, 4)
.pipe(
// Using higher-order operator
switchMap(
next => of(next)
.pipe(
map(
v => {
// Throw an error if input value equals to 2
if (v === 2) {
throw new Error('My Error');
}
return next;
}
),
// Catch error and return the default value
catchError(error => of(0))
)
),
)
.subscribe(
value => console.log('Success: ' + value),
err => console.log('Handle the error: ' + err),
() => console.log('complete'),
);
Result:
Success: 1
Success: 0
Success: 3
Success: 4
complete
No comments:
Post a Comment