RxJS presents a lot of ways to handle errors, and I'm having a hard time understanding each of them and where they're used. The more I learn about RxJS, the less I understand it.
If I'm using a pipe, there's catchError.
If I'm using tap inside the pipe, there's the optional error parameter.
If I'm using subscribe, there's also the optional error parameter.
Where do I want to use one error handler over the other? What are the use cases for the optional error parameters? If I'm using tap's error parameter, do I still need to use catchError? If I have catchError, do I still need to use subscribes error parameter?
I want to better understand each of the error handlers, and what the proper way to go about error handling is.
CodePudding user response:
Handling the error using the subscribe error callback can do your job but it has limits in case you want to emit an alternative value in case of an error. (replacement value)
For example imagine that you are waiting for your observable to emit a list of users but you want to get an empty array in case of an error, you can't do that in the error callback inside your subscribe call but you can do it using catchError
getUsers$.pipe(
catchError(error => of([]))
)
You use multple catchError operator to throw an error and add a replacement value
getUsers$.pipe(
catchError(error => {
return throwError(error);
}),
catchError(error => {
return of([]);
})
).subscribe(
users=> console.log('users', users),
err => console.log('Error', err),
)
that case the thrown error will never reach the subscribe handler function, you will have this in your console log
users []
CodePudding user response:
RxJS streams are designed in the way an error causes a collapse of the whole stream. To prevent this behaviour RxJS provides a catchError
operator. It simply catch an error; input stream of catchError collapsed, but output stream of catchError is preserved (if catchError does not throw error too).
Example: Handled API error
actions$.pipe(
filter(action => action.type === 'fetchData'),
mergeMap(() => fetchData().pipe(
map(data => ({ type: 'dataFetchSuccess', data })
catchError(error => of('dataFetchError'))
))
)
Note: When the fetchData
fails, the actions$ stream doesn't fail and is able to process next value and fetch the data again.
Operator tap
is designed to use for side effects, it has no effect on the stream. In other words it does not change the stream in any way.
Example: Operator tap
is able to perform side effect for all cases: next
, error
and complete
.
actions$.pipe(
tap(console.log, console.error, () => console.log('complete')),
// or
tap({
next: console.log,
error: console.error,
complete: console.log('complete'),
}),
)
Error handler in subscribe
is called if stream has collapsed due to an error. (Note: Practically catchError
operator subscribes to input stream with an error handler, watches and processes the error.)
Conclusion:
For simple stream that could be collapsed due to an error we can subscribe
to the stream with error handler.
Use catchError
for complicated stream that cannot be collapsed entirely.