Check out a free preview of the full Asynchronous Programming in JavaScript (with Rx.js Observables) course

The "Catching Errors" Lesson is part of the full, Asynchronous Programming in JavaScript (with Rx.js Observables) course featured in this preview video. Here's what you'd learn in this lesson:

Jafar demonstrates how to handle errors that may occur when making network requests. The error handler is passed as the second parameter to the forEach and the retry function can be used to designate the number of attempts the Observable should make. This error handler will get called if after the desired number of attempts has been reached.


Transcript from the "Catching Errors" Lesson

>> [MUSIC]

>> Jafar Husain: So can we make it better? Is it is it ready yet to ship, our autocomplete box example? What do you think? How can I improve on this?
>> Off Camera 1: They need a message if there's an error or if there's nothing returning.
>> Jafar Husain: That's true and what I would do, what I would do if we weren't happening to use a JSONP API what I would also be doing and what I should do is adding an error handler.

So let's pretend that we're not using a JSONP because we're never gonna get, at least well technically you can get an error. But when you're using JSONP under the hood cuz it's attaching a script tag there's no way to get a message that that error happened. And so let's imagine though in practice you're probably not going to using JSONP in production you're going to be using actually XHRs.

And so let's imagine that the error that this getWikipediaSearchResults could in fact on error the observable could on error us. Well, what's gonna happen is even though it's the error is going to occur here, it's the observable's job to forward it on up to the first, to the forEach call.

And so we can handle it right here. So this is like our catch statement. We don't have to put any error handling code in here whatsoever, because the observable will do what the JavaScript Runtime does for us with synchronous exceptions. The JavaScript Runtime, every single time we call a function, we don't have to put try catch around it, right?

We can put try catch around a big block of synchronous code and if an error occurs anywhere in there, it's gonna bubble up and then we can catch it using try catch. The same thing is done here, but this time by the observable and not the JavaScript Runtime.

So in other words, if the map functions, so the map function creates a new observable using another observable as its source, and when you foreach over the map observable it foreaches over its source. And if the source observable on errors, sends an on error message back, it just forwards that on error along.

And so it's only when somebody provides an on error handler, right here, like here at the end with the foreach, that that error, can be handled once and for all. We can just sort of catch it. So an error that occurs anywhere in here, we can catch here.

Now this is 100 times better. The nested callbacks because when you have nested callbacks, like you get in Node.js for example, if an error occurs you have to be sort of at every point handling that error. So, if I have a callback like this right? Callback API, some argument and then I have to pass a callback because this is what it looks like in Node.js..

And then and I'll call some other callback cuz I want to do one thing after another thing. This is how it works in Node.js. At every stage here I have to be prepared for the eventuality of getting an error. And then I have to either forward it up, or clean up any subscriptions that I've added here.

What if I subscribe to an event here? Well if an error occurs down here I have to remember to unsubscribe from that event. It gets very, very complicated very, very fast. Whereas with an observable as soon as it on errors, just like when on completes it will clean up after itself.

So, that's an important key thing that I may have mentioned before, when observable stream completes, when it tells you on completed, I'm never going to send you any more data again, well it frees your subscription. The same thing applies if it tells you an error occurred. It will free your subscription automatically, so it will clean up after itself.

Much like when an error occurs in the middle of a JavaScript code, and there's a try catch, it unwinds the stack and deallocates all of the variables that you created in your function. All right so all those things are deallocated and then they can be garbage collected if there's no other references to it.

So the point is it's just like when you're dealing with synchronous code. You can count on the fact that when an error is forwarded up the chain all of the individual event subscriptions that were added when you forged over observables have been unsubscribed. Does that makes sense? So this dramatically decreases the complexity of working with async code.

If you, it's a choice really between learning this definitely complicated loopless style of programming. It's definitely hard to learn that it then when you learn it. Or dealing with a thousand different callback APIs and subscribing to subscriptions, unhooking subscriptions, error handling, that's a problem you have to solve every single time you start a new app.

Right? Every single time you build an asynchronous app, you've gotta deal with handling all these callbacks and making sure you don't have memory leaks. Better to learn five functions and get really good at loopless programming so you don't have to worry about that ever again. Cuz once you've got that skill, it's with you forever.

That makes sense? The complexity we're trying to get rid of here. So, let's go back, so here, what would I put in here? What would be the thing, I mean, the only reason that an error would occur here, is that the network error. Sorry, gotta question in the back.

>> Off Camera 2: Yeah, I'm just asking about can you use retry on the JSON calls?
>> Jafar Husain: That was just what I was getting to. I love this audience it's great. Absolutely because when we hit Wikipedia, it could go down. I mean Wikipedia is not up 100% percent of the time.

Netflix has awesome up time. We've got great up time, I think it's, I don't wanna quote a number cuz it'll be wrong. But it's up there. It's definitely about 97% percent, but that still means when you look at millions and millions of requests every day a large number of requests fail.

So rather than just throw up our hands if one little server happens to be misbehaving we should probably retry this request. Right? So, now again, in this particular instance just remember that the JSONP is never gonna error but in reality, when you're working in network, you'll be against XHRs and it may well error.

So although it's not really specifically practical for this call, if you were doing this in production you'd wanna do this. You'd want to retry because if it errors you'll just automatically schedule another retry. And if it errors, only if it errors three times will that error actually make it through down here to our error handler.

And by the time it's failed three times, yeah it's a pretty good bet that the server's down right now. So instead of just continuing to hammer your server, which is probably not a good idea, right, because if the server having problems the last thing it needs is a million more retries.

You wanna just say,
>> Jafar Husain: Maybe a little bit nicer language.
>> Off Camera 1: [LAUGH]
>> Jafar Husain: I don't know, but you get the picture right? That's for cases where you're really, it's just like you catch an error, you've done your best, right? You can't do any better. So, I like that answer out there.

Is there another situation where I wouldn't want to send a network request?
>> Jafar Husain: Let's try this. First of all I just wanna make sure the still works. I'm all fork this right now. And then let's run.
>> Off Camera 2: Someone's asking what's the retry rate?
>> Jafar Husain: Rate? So there's no rate per se, what happens is retry, so from now on I'm going to try and anthropomorphize these operations, right?

So I'm an observable, let's imagine I'm an observable. And she is a map version of me. So in other words because when you call a map you create another observable that's a mapped version of the previous observable. Right? So now, let's say you wanna take everything that I onNext.

And then she's gonna add one to it and onNext it to him. He's gonna consume the data from her, right? So what he says to her is he says, foreach. And then she says to me foreach. And then I say on next one and then you say to him, on next two.

Yeah, that's good, let's keep it going. On next two.
>> Off Camera 4: On next two.
>> Jafar Husain: On next three, right? You're adding one to each one, right? On next three.
>> Off Camera 4: On next four.
>> Jafar Husain: Yes. So now let's play it differently, instead of the map, she's gonna be the retry function.

Okay, she's gonna be the retry function, and you're gonna say to her, play along with me here.
>> Off Camera 1: Okay.
>> Jafar Husain: What are you gonna, how you gonna get the data out of her, she's an observable?
>> Off Camera 1: ForEach.
>> Jafar Husain: ForEach. You say to her forEach and I in the network request right.

She's the retry observable that's created when you call retry on an observable. So you're gonna say to me what?
>> Off Camera 4: ForEach.
>> Jafar Husain: ForEach. And I'm gonna take my sweet time going off the to network. And then eventually I'm to say, no error. And then what are you gonna say to him?

>> Off Camera 4: Error.
>> Jafar Husain: No, you're the retry operation so you've got a little counter, right? And so what you're going to say is, I'm gonna increment that counter from zero to one. And then what are you gonna say to me?
>> Off Camera 4: Retry.
>> Jafar Husain: ForEach, right? So I take my time make a network request.

[SOUND] On error.
>> Off Camera 4: ForEach.
>> Jafar Husain: OnNext some data. What do you do?
>> Off Camera 4: Some data plus one.
>> Jafar Husain: Well you know I'm not pejorable. You were trying, right? So you guarantee transforming the data, you're just sending it. So do we see how this works, right? It's just each step is just like another person, you just add another person in the chain.

When somebody says forEach, the forEaches cascade through all the way to the data source. Right? And so that's retries job is to just insert itself into the middle operation. And just if it gets a few errors it keeps incrementing a counter until that counter goes up above a certain level and then instead of telling me forEach again she's just going to tell him error.

Does that makes sense?

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now