RxJS – Part 5 – RxJS error handling

This entry is part 5 of 6 in the RxJS series

Error handling

In the first post we saw that we have 3 main methods on Observer object: next, error and complete. Lets focus on error() method. When does it gets called? Lets see the code example.

For that scenario we will use almost the same code that we used in second post when we used Observable.create(). We will have only few minor changes. We will add another word to our words array. Furthermore, we will add a condition in the for loop to execute observer.error() method once we run into ‘badword‘.

 As a result we get the following output:

We can see from the output that we have an uncaught exception and once again complete() did not run. Also notice that last console.log never happened. That’s because we had an uncaught exception.

What if we include error method when subscribing to our Observable source?

In this case we get the following output:

From this we can notice that error method did execute. However, complete method did not execute. Calling observer.error() is similar to raising exception in regular code and will cause Observable to stop processing the array. Furthermore, we can see that last console.log did run in this case.

If we leave all the code same but we replace observer.error call with throw new Error:

This time we will get an uncaught exception and last line – console.log('after subscribe') will not run!

If you want to play around with code in editor and see what happens you can find the plunker version at this link.

 

Catch me please!

We saw we can use throw with RxJS but what about catch? We cannot use try {} catch {}. It would be useless since we are dealing with asynchronous functions and operators. By the time most of the code executes we will already be outside of the try/catch block. 

As we saw if an unexpected error happens in one of the operators we get an uncaught exception and things break:

Now the output:

Now, that is something that makes every developer sad. How can we handle this? Just like Promises have .catch method we also have the catch operator in RxJS.

Lets see the output now:

There is no error now! However, we did not get all the values. Observable execution completed after second word. Maybe we do not want to handle it like this? Lets assume that error that came from map() was an exception that happened in our code and was not so obvious. Maybe we want to throw our own error from catch operator?

Now we get the following output:

In both cases our Observable stops at error. That is because once an error is encountered in Observable it basically unsubscribes and will not continue on to next element.

 

Can we do better?

Maybe we are using RxJS to get some data from our API and it could be unavailable for few seconds or so. It would be great if we could retry our request one more time? or few more times? Or maybe we want to try again in 5 seconds? Worry not! RxJS has retry and retryWhen operators and they can do all of that!

And the output:

That seems quite crude. Could be useful in some cases but we are usually gonna opt out for something more sophisticated. That is why RxJS has retryWhen operator.

retryWhen takes an Observable of errors as its only parameter and it expects us to return an Observable. And how does it know when to retry? It is quite simple actually. When that Observable that we return from retryWhen emits a value.  That is what triggers it. After that Observable on which retryWhen is operating on will try again its logic that caused the error in first place.

And the output:

That might not be what we want. Maybe we want to error out after few times:

We are retrying for our logic to complete 3 times. Every time there is a delay of 2 seconds.

We get the following output:

We could extract the method inside of our retryWhen operator and implement it as reusable function with different approach. We could make few of those and use them in our application. Once a method is extracted and just forwarded to operator it definitely makes code look better as well.

 

Summary

We saw how we can deal with errors with RxJS.  Hopefully you understood what is the difference when we are dealing with an error that happened purposefully and an error that was not properly handled.

If we get an unhandled error neither complete nor error method will execute. However, if handled error occurs either error or complete method will execute but never both of them!

Also, we saw how we can use retry operator and its more sophisticated cousin retryWhen.

That is all for now. In the next post we will talk about real world use cases and see RxJS in action.



RxJS Series Navigation: Previous post: << RxJS – Part 4 – Operators
Next post: RxJS – Part 6 – Chat application with RxJS >>



Ibrahim Šuta

Software Consultant interested and specialising in ASP.NET Core, C#, JavaScript, Angular, React.js.