Besides catch, the other commonly used error handling operator is retry, and it does what the name hints. If it sees an error, it resubscribes to the input Observable, which is bar. If we look at the marble diagram, bar is the input Observable. When we call retry on this, it will simply run the input Observable bar.
When it sees an error, it will replace the error with bar again. Then, it just keeps on replacing errors with bar infinitely, so this goes on forever. If we try to run that, we see, "ABCD ABCD," and it keeps on doing that, because it's retrying forever.
Retry also takes an argument, which is the number of retries, here. We can give, for instance, two. That means that it will only try again two times. Once it sees the error, it will try again the first attempt, and then it sees an error again, it will try a second time. Then, after it tried two times, again, then it will just quit and emit the error.
If you run this, we see, "ABCD." Again, this is the first try, and the second try now, and then it quits, and it emits the error.
Retry here, when given an argument for the number of retries, is particularly useful when retrying HTTP requests to the server, for instance. With this operator, you can easily choose to retry a maximum of three times, but after that, just emit the error.
There's a variant of retry called retryWhen where instead of immediately subscribing to bar again once an error happens, you can tell when to retry or, basically, when to subscribe to bar again. That's done by giving a function where the input is the error Observable and the output is another Observable that tells when should we subscribe again to bar.
In this case, I'm just going to write error Observable delayed by one second. Looking at the marble diagram for retryWhen, what is really this error Observable? Let's remember, first, that an error can only happen once in an Observable. It's also true that these moments in time, like here and here, happen because of an error.
RetryWhen is able to collect these errors and emit them as these e values in the error Observable. This is what error Observable is. That's just a trick in order to capture an error.
If you remember, Observables can emit next values, error values, and complete values. What error Observable is, it gets an error from the bar, and it converts that to a next and emits that on the error Observable.
That's why we can have this. This is actually an Observable that only has next values. It doesn't have an error. It happens to be that these values are actually errors. Once we take this and we delay it for some amount of time, that's how we are able to retry after one second has passed since the error emission. Something like this.
Now, when we run that, we can see that it waits for a while. After that while, it continues again. You can make this even larger, like three. This is very useful, also, for server requests where you're able to retry not immediately but after some time has passed.
Both retry and retryWhen are slight variations of catch, but they're very useful as error handling operators.