1 00:00:01,120 --> 00:00:03,120 In this video, let's talk about something 2 00:00:03,120 --> 00:00:06,770 that we have in node.js called unhandled rejections 3 00:00:06,770 --> 00:00:09,543 and then learn how we can actually handle them. 4 00:00:10,970 --> 00:00:14,400 So at this point, we have successfully handled errors 5 00:00:14,400 --> 00:00:16,330 in our express application 6 00:00:16,330 --> 00:00:19,970 by passing operational asynchronous errors down 7 00:00:19,970 --> 00:00:22,410 into a global error handling middleware. 8 00:00:22,410 --> 00:00:26,200 This, then sends relevant error messages back to the client 9 00:00:26,200 --> 00:00:30,510 depending on the type of error that occurred, right? 10 00:00:30,510 --> 00:00:34,730 However, there might also occur errors outside of express 11 00:00:34,730 --> 00:00:38,520 and a good example for that in our current application 12 00:00:38,520 --> 00:00:40,810 is the mongodb database connection. 13 00:00:40,810 --> 00:00:43,700 So imagine that the database is down for some reason 14 00:00:43,700 --> 00:00:46,000 or for some reason, we cannot log in. 15 00:00:46,000 --> 00:00:47,920 And in that case, there are errors 16 00:00:47,920 --> 00:00:49,610 that we have to handle as well. 17 00:00:49,610 --> 00:00:52,800 But they didn't occur inside of our express application 18 00:00:52,800 --> 00:00:55,810 and so, of course, our error handler that we implemented 19 00:00:55,810 --> 00:00:58,560 will not catch this errors, right? 20 00:00:58,560 --> 00:01:01,790 And so just to test what happens, let's go ahead 21 00:01:01,790 --> 00:01:05,110 and change our mongodb password, okay? 22 00:01:05,110 --> 00:01:06,960 Because that way, we're not gonna be able 23 00:01:06,960 --> 00:01:10,180 to connect to the database, right? 24 00:01:10,180 --> 00:01:13,110 And so we should then get some kind of error, 25 00:01:13,110 --> 00:01:15,510 and so let's go here to our server file 26 00:01:15,510 --> 00:01:18,633 and save it in order to reload our server, 27 00:01:20,710 --> 00:01:23,040 let's increase it here, and indeed, 28 00:01:23,040 --> 00:01:26,120 here we have an unhandled promise rejection. 29 00:01:26,120 --> 00:01:29,510 And so that is actually the topic of this video. 30 00:01:29,510 --> 00:01:33,600 So an unhandled promise rejection means that somewhere 31 00:01:33,600 --> 00:01:37,140 in our code, there is a promise that got rejected. 32 00:01:37,140 --> 00:01:41,270 But that rejection has not been handled anywhere, all right? 33 00:01:41,270 --> 00:01:44,920 And down here, you also see a deprecation warning 34 00:01:44,920 --> 00:01:48,008 which says that in the future unhandled rejections 35 00:01:48,008 --> 00:01:51,710 will simply exit the node program that's running, 36 00:01:51,710 --> 00:01:54,940 which may not always be what you want, okay? 37 00:01:54,940 --> 00:01:57,450 So let's fix this problem and get rid 38 00:01:57,450 --> 00:02:00,000 of this unhandled promise rejection. 39 00:02:00,000 --> 00:02:01,910 Now, in this simple example here, 40 00:02:01,910 --> 00:02:03,270 it would be actually quite easy 41 00:02:03,270 --> 00:02:05,770 to handle that rejection, right? 42 00:02:05,770 --> 00:02:08,060 All we'll have to do would to come here 43 00:02:08,060 --> 00:02:11,550 to this piece of code where our connection is actually done 44 00:02:11,550 --> 00:02:14,100 and then, add a catch handler there, right? 45 00:02:14,100 --> 00:02:16,580 So a bit like this, and then in here, 46 00:02:16,580 --> 00:02:18,640 we could handle that rejection 47 00:02:18,640 --> 00:02:20,970 and would then no longer get this error. 48 00:02:20,970 --> 00:02:22,820 Let me just quickly show that to you. 49 00:02:29,905 --> 00:02:31,960 So try it again. 50 00:02:31,960 --> 00:02:35,630 And so now, you get error which is of course, 51 00:02:35,630 --> 00:02:37,950 the result of this log here, 52 00:02:37,950 --> 00:02:41,010 but of course, we get no unhandled promise rejection, 53 00:02:41,010 --> 00:02:45,060 again, because we actually handled it here, all right? 54 00:02:45,060 --> 00:02:48,580 So this would work, of course, but I really want to show you 55 00:02:48,580 --> 00:02:51,720 how to globally handle unhandled rejected promises, 56 00:02:51,720 --> 00:02:54,680 because in a bigger application, it can become a bit 57 00:02:54,680 --> 00:02:57,860 more difficult to always keep track of all the promises 58 00:02:57,860 --> 00:03:00,590 that might become rejected at some point, okay? 59 00:03:00,590 --> 00:03:03,280 And so at some point, you might have some unhandled 60 00:03:03,280 --> 00:03:06,690 promise rejection somewhere and so let me show you 61 00:03:06,690 --> 00:03:09,860 how to deal with that globally basically. 62 00:03:09,860 --> 00:03:14,070 And so let's now learn how to handle unhandled rejections 63 00:03:14,070 --> 00:03:16,160 and we're gonna do that right here. 64 00:03:16,160 --> 00:03:19,530 And so remember how in one of the first section 65 00:03:19,530 --> 00:03:21,900 of the course, we talked about events 66 00:03:21,900 --> 00:03:24,080 and event listeners, right? 67 00:03:24,080 --> 00:03:28,010 And so now, it's time to actually use that knowledge. 68 00:03:28,010 --> 00:03:30,940 So each time that there is an unhandled rejection 69 00:03:30,940 --> 00:03:34,180 somewhere in our application, the process object 70 00:03:34,180 --> 00:03:37,470 will emit an object called unhandled rejection 71 00:03:37,470 --> 00:03:41,223 and so we can subscribe to that event just like this. 72 00:03:42,250 --> 00:03:46,903 So process.on, remember, and then the name of the event, 73 00:03:48,004 --> 00:03:52,053 unhandled rejection, 74 00:03:52,930 --> 00:03:55,240 and then the callback function here 75 00:03:55,240 --> 00:03:59,369 receives an error, and so let's actually go ahead 76 00:03:59,369 --> 00:04:02,793 and log the error to the console. 77 00:04:03,780 --> 00:04:08,653 So let's use err.name and err.message. 78 00:04:09,620 --> 00:04:11,640 So these are kind of some defaults 79 00:04:12,500 --> 00:04:16,073 that we have on all errors in node.js, all right? 80 00:04:17,570 --> 00:04:20,930 Okay, and after saving, we already, down here 81 00:04:20,930 --> 00:04:24,410 get the name of the error and also the error message. 82 00:04:24,410 --> 00:04:27,940 So bad authentication which is because, of course, 83 00:04:27,940 --> 00:04:29,490 we have the wrong password. 84 00:04:29,490 --> 00:04:32,360 And so right now, the unhandled promise rejection 85 00:04:32,360 --> 00:04:33,960 is now actually handled. 86 00:04:33,960 --> 00:04:37,430 And of course, not just the one from this failed connection 87 00:04:37,430 --> 00:04:40,410 but any other promise rejection that we might not catch 88 00:04:40,410 --> 00:04:44,260 somewhere in the application is handled here in this final, 89 00:04:44,260 --> 00:04:46,880 let's call it safety net, all right? 90 00:04:46,880 --> 00:04:49,890 So we always have to assume that we as programmers 91 00:04:49,890 --> 00:04:51,410 are gonna make errors. 92 00:04:51,410 --> 00:04:54,740 And so it's always best to have a central place like this 93 00:04:54,740 --> 00:04:56,560 to handle all promise rejections 94 00:04:56,560 --> 00:04:59,132 like a last safety net, all right? 95 00:04:59,132 --> 00:05:01,800 Now, if we really have like some problem 96 00:05:01,800 --> 00:05:04,890 with the database connection, like we have in this example, 97 00:05:04,890 --> 00:05:07,840 then our application is not gonna work at all. 98 00:05:07,840 --> 00:05:09,760 And so all we can really do here 99 00:05:09,760 --> 00:05:12,820 is to shut down our application, all right? 100 00:05:12,820 --> 00:05:17,053 So to shutdown the application, we use process.exit. 101 00:05:18,140 --> 00:05:20,420 And we actually already used that before 102 00:05:20,420 --> 00:05:22,850 in that script where we imported all the data 103 00:05:22,850 --> 00:05:27,080 into the database from the JSON file, remember? 104 00:05:27,080 --> 00:05:29,660 So process.exit and then in here, 105 00:05:29,660 --> 00:05:31,810 we can actually pass a code. 106 00:05:31,810 --> 00:05:34,140 And the code zero stands for a success 107 00:05:34,140 --> 00:05:36,800 and one stands for uncaught exception. 108 00:05:36,800 --> 00:05:40,230 And so that's the one that's usually used here, all right? 109 00:05:40,230 --> 00:05:43,400 So usually, you will always see it like this. 110 00:05:43,400 --> 00:05:46,970 And let's just add like a log here, console.log 111 00:05:50,293 --> 00:05:51,973 unhandler the rejection, 112 00:05:56,020 --> 00:05:57,560 something like this. 113 00:05:57,560 --> 00:05:59,860 So you see, I really like this, this one here. 114 00:06:02,910 --> 00:06:04,650 Just letting this are node... 115 00:06:04,650 --> 00:06:06,730 Not really user but our log 116 00:06:06,730 --> 00:06:09,320 that we're shutting down, all right? 117 00:06:09,320 --> 00:06:12,330 And so now, you see that the app actually crashed. 118 00:06:12,330 --> 00:06:16,515 And so that's because of this process.exit here, all right? 119 00:06:16,515 --> 00:06:18,860 Now, there is just one problem with the way 120 00:06:18,860 --> 00:06:20,480 we implemented it right now 121 00:06:20,480 --> 00:06:23,430 and that is, that the way we implement it here 122 00:06:23,430 --> 00:06:26,990 so just process.exit is a very abrupt way 123 00:06:26,990 --> 00:06:30,420 of ending the program because this will just immediately 124 00:06:30,420 --> 00:06:34,030 abort all the requests that are currently still running 125 00:06:34,030 --> 00:06:38,300 or pending and so that might not be a good idea, okay? 126 00:06:38,300 --> 00:06:41,550 And so usually, what we do is to shutdown gracefully 127 00:06:41,550 --> 00:06:44,210 where we first close the server and only then, 128 00:06:44,210 --> 00:06:47,140 we shut down the application, okay? 129 00:06:47,140 --> 00:06:47,973 So let's... 130 00:06:47,973 --> 00:06:51,440 Before we do that, we need to save the server here 131 00:06:51,440 --> 00:06:55,670 basically to a variable, okay? 132 00:06:55,670 --> 00:06:59,650 And so the result of calling app.listen is a server 133 00:06:59,650 --> 00:07:04,650 and to now, on that server, we can then say server.close 134 00:07:05,810 --> 00:07:08,400 which will, as the name says, close the server 135 00:07:08,400 --> 00:07:10,490 and then after that's done, 136 00:07:10,490 --> 00:07:14,810 it will run this callback function that we passed into it 137 00:07:14,810 --> 00:07:16,130 and so it's only here, 138 00:07:16,130 --> 00:07:19,310 where we then shut down the server, okay? 139 00:07:19,310 --> 00:07:22,240 And so by doing this, by doing server.close, 140 00:07:22,240 --> 00:07:25,630 we give the server, basically time to finish all the request 141 00:07:25,630 --> 00:07:28,890 that are still pending or being handled at the time, 142 00:07:28,890 --> 00:07:31,180 and only after that, the server is then basically 143 00:07:31,180 --> 00:07:32,910 killed, all right? 144 00:07:32,910 --> 00:07:34,620 So when we give it a safe, it's not gonna look 145 00:07:34,620 --> 00:07:37,020 exactly the same because, (laughs) yeah, 146 00:07:37,020 --> 00:07:39,880 we're like the only ones that really accessing 147 00:07:39,880 --> 00:07:42,850 this application but in the real world scenario, 148 00:07:42,850 --> 00:07:45,960 we should always do it like this, okay? 149 00:07:45,960 --> 00:07:48,200 And of course, that's not really ideal 150 00:07:48,200 --> 00:07:50,520 that the application crashed, right? 151 00:07:50,520 --> 00:07:53,120 Because right now, of course, the app is not running, 152 00:07:53,120 --> 00:07:55,448 it's not working at all, right? 153 00:07:55,448 --> 00:07:59,570 And so usually, in a production app on a web server, 154 00:07:59,570 --> 00:08:01,690 we will usually have some tool in place 155 00:08:01,690 --> 00:08:05,100 that restarts the application right after it crashes, 156 00:08:05,100 --> 00:08:08,120 or also some of the platforms that host node.js 157 00:08:08,120 --> 00:08:11,164 will automatically do that on their own, okay? 158 00:08:11,164 --> 00:08:13,920 Because, of course, we don't wanna leave the application 159 00:08:13,920 --> 00:08:15,590 hanging like this forever. 160 00:08:15,590 --> 00:08:18,420 So that's not useful either, all right? 161 00:08:18,420 --> 00:08:20,410 And so basically, this is how you handle 162 00:08:20,410 --> 00:08:22,590 unhandled rejected promises. 163 00:08:22,590 --> 00:08:25,130 So again, basically, we are listening 164 00:08:25,130 --> 00:08:27,930 to this unhandled rejection event, 165 00:08:27,930 --> 00:08:30,100 which then allows us to handle all the errors 166 00:08:30,100 --> 00:08:32,280 that occur in asynchronous code 167 00:08:32,280 --> 00:08:34,470 which were not previously handled. 168 00:08:34,470 --> 00:08:38,050 But now, you might ask, what about the synchronous code? 169 00:08:38,050 --> 00:08:40,110 Where are we gonna handle that? 170 00:08:40,110 --> 00:08:43,020 And the answer to that lies, as you can imagine, 171 00:08:43,020 --> 00:08:44,523 in the next video.