Instructor: In this video, let's talk about something
that we have in node.js called unhandled rejections
and then learn how we can actually handle them.
So at this point, we have successfully handled errors
in our express application
by passing operational asynchronous errors down
into a global error handling middleware.
This, then sends relevant error messages back to the client
depending on the type of error that occurred, right?
However, there might also occur errors outside of express
and a good example for that in our current application
is the mongodb database connection.
So imagine that the database is down for some reason
or for some reason, we cannot log in.
And in that case, there are errors
that we have to handle as well.
But they didn't occur inside of our express application
and so, of course, our error handler that we implemented
will not catch this errors, right?
And so just to test what happens, let's go ahead
and change our mongodb password, okay?
Because that way, we're not gonna be able
to connect to the database, right?
And so we should then get some kind of error,
and so let's go here to our server file
and save it in order to reload our server,
let's increase it here, and indeed,
here we have an unhandled promise rejection.
And so that is actually the topic of this video.
So an unhandled promise rejection means that somewhere
in our code, there is a promise that got rejected.
But that rejection has not been handled anywhere, all right?
And down here, you also see a deprecation warning
which says that in the future unhandled rejections
will simply exit the node program that's running,
which may not always be what you want, okay?
So let's fix this problem and get rid
of this unhandled promise rejection.
Now, in this simple example here,
it would be actually quite easy
to handle that rejection, right?
All we'll have to do would to come here
to this piece of code where our connection is actually done
and then, add a catch handler there, right?
So a bit like this, and then in here,
we could handle that rejection
and would then no longer get this error.
Let me just quickly show that to you.
So try it again.
And so now, you get error which is of course,
the result of this log here,
but of course, we get no unhandled promise rejection,
again, because we actually handled it here, all right?
So this would work, of course, but I really want to show you
how to globally handle unhandled rejected promises,
because in a bigger application, it can become a bit
more difficult to always keep track of all the promises
that might become rejected at some point, okay?
And so at some point, you might have some unhandled
promise rejection somewhere and so let me show you
how to deal with that globally basically.
And so let's now learn how to handle unhandled rejections
and we're gonna do that right here.
And so remember how in one of the first section
of the course, we talked about events
and event listeners, right?
And so now, it's time to actually use that knowledge.
So each time that there is an unhandled rejection
somewhere in our application, the process object
will emit an object called unhandled rejection
and so we can subscribe to that event just like this.
So process.on, remember, and then the name of the event,
unhandled rejection,
and then the callback function here
receives an error, and so let's actually go ahead
and log the error to the console.
So let's use err.name and err.message.
So these are kind of some defaults
that we have on all errors in node.js, all right?
Okay, and after saving, we already, down here
get the name of the error and also the error message.
So bad authentication which is because, of course,
we have the wrong password.
And so right now, the unhandled promise rejection
is now actually handled.
And of course, not just the one from this failed connection
but any other promise rejection that we might not catch
somewhere in the application is handled here in this final,
let's call it safety net, all right?
So we always have to assume that we as programmers
are gonna make errors.
And so it's always best to have a central place like this
to handle all promise rejections
like a last safety net, all right?
Now, if we really have like some problem
with the database connection, like we have in this example,
then our application is not gonna work at all.
And so all we can really do here
is to shut down our application, all right?
So to shutdown the application, we use process.exit.
And we actually already used that before
in that script where we imported all the data
into the database from the JSON file, remember?
So process.exit and then in here,
we can actually pass a code.
And the code zero stands for a success
and one stands for uncaught exception.
And so that's the one that's usually used here, all right?
So usually, you will always see it like this.
And let's just add like a log here, console.log
unhandler the rejection,
something like this.
So you see, I really like this, this one here.
Just letting this are node...
Not really user but our log
that we're shutting down, all right?
And so now, you see that the app actually crashed.
And so that's because of this process.exit here, all right?
Now, there is just one problem with the way
we implemented it right now
and that is, that the way we implement it here
so just process.exit is a very abrupt way
of ending the program because this will just immediately
abort all the requests that are currently still running
or pending and so that might not be a good idea, okay?
And so usually, what we do is to shutdown gracefully
where we first close the server and only then,
we shut down the application, okay?
So let's...
Before we do that, we need to save the server here
basically to a variable, okay?
And so the result of calling app.listen is a server
and to now, on that server, we can then say server.close
which will, as the name says, close the server
and then after that's done,
it will run this callback function that we passed into it
and so it's only here,
where we then shut down the server, okay?
And so by doing this, by doing server.close,
we give the server, basically time to finish all the request
that are still pending or being handled at the time,
and only after that, the server is then basically
killed, all right?
So when we give it a safe, it's not gonna look
exactly the same because, (laughs) yeah,
we're like the only ones that really accessing
this application but in the real world scenario,
we should always do it like this, okay?
And of course, that's not really ideal
that the application crashed, right?
Because right now, of course, the app is not running,
it's not working at all, right?
And so usually, in a production app on a web server,
we will usually have some tool in place
that restarts the application right after it crashes,
or also some of the platforms that host node.js
will automatically do that on their own, okay?
Because, of course, we don't wanna leave the application
hanging like this forever.
So that's not useful either, all right?
And so basically, this is how you handle
unhandled rejected promises.
So again, basically, we are listening
to this unhandled rejection event,
which then allows us to handle all the errors
that occur in asynchronous code
which were not previously handled.
But now, you might ask, what about the synchronous code?
Where are we gonna handle that?
And the answer to that lies, as you can imagine,
in the next video.