﻿1
00:00:01,300 --> 00:00:03,370
‫Let's now take a minute to learn about

2
00:00:03,370 --> 00:00:06,370
‫the asynchronous nature of Node.js,

3
00:00:06,370 --> 00:00:09,510
‫which includes absolutely fundamental topics,

4
00:00:09,510 --> 00:00:13,010
‫like synchronous, asynchronous, blocking,

5
00:00:13,010 --> 00:00:15,140
‫and non-blocking code.

6
00:00:15,140 --> 00:00:17,810
‫And all of this will be really important

7
00:00:17,810 --> 00:00:21,090
‫in order to understand everything that's coming up

8
00:00:21,090 --> 00:00:22,503
‫throughout this section.

9
00:00:24,240 --> 00:00:27,620
‫So this piece of code that we wrote in the last lecture,

10
00:00:27,620 --> 00:00:31,830
‫to read a file and then, save it's content into a variable,

11
00:00:31,830 --> 00:00:34,400
‫was in a so-called synchronous way,

12
00:00:34,400 --> 00:00:36,840
‫which simply means that each statement

13
00:00:36,840 --> 00:00:41,330
‫is basically processed one after another, line by line.

14
00:00:41,330 --> 00:00:42,540
‫In this example,

15
00:00:42,540 --> 00:00:45,630
‫first, the file system module is required,

16
00:00:45,630 --> 00:00:47,630
‫then, the file is read,

17
00:00:47,630 --> 00:00:50,900
‫and then, we log the result to the console.

18
00:00:50,900 --> 00:00:53,340
‫So you see that each line of code

19
00:00:53,340 --> 00:00:57,340
‫basically waits for the result of the previous line.

20
00:00:57,340 --> 00:00:59,440
‫Now, this can become a problem,

21
00:00:59,440 --> 00:01:01,500
‫especially with slow operations,

22
00:01:01,500 --> 00:01:04,190
‫because each line blocks the execution

23
00:01:04,190 --> 00:01:05,710
‫of the rest of the code.

24
00:01:05,710 --> 00:01:08,120
‫And so, we say that synchronous code

25
00:01:08,120 --> 00:01:12,290
‫is also called blocking code because, again,

26
00:01:12,290 --> 00:01:15,080
‫a certain operation can only be executed

27
00:01:15,080 --> 00:01:17,740
‫after the one before has finished.

28
00:01:17,740 --> 00:01:20,850
‫And because of the way Node.js was designed,

29
00:01:20,850 --> 00:01:24,220
‫this turns into a huge problem, as we'll see in detail

30
00:01:24,220 --> 00:01:26,190
‫in the next slide.

31
00:01:26,190 --> 00:01:28,500
‫So the solution to this problem in Node

32
00:01:28,500 --> 00:01:32,160
‫is to use asynchronous, non-blocking code.

33
00:01:32,160 --> 00:01:35,380
‫So in asynchronous code, we upload heavy work

34
00:01:35,380 --> 00:01:38,470
‫to basically be worked on in the background.

35
00:01:38,470 --> 00:01:40,820
‫And then, once that work is done,

36
00:01:40,820 --> 00:01:43,370
‫a callback function that we register before

37
00:01:43,370 --> 00:01:45,730
‫is called to handle the result.

38
00:01:45,730 --> 00:01:47,540
‫And during all that time,

39
00:01:47,540 --> 00:01:50,380
‫the rest of the code can still be executing

40
00:01:50,380 --> 00:01:52,910
‫without being blocked by the heavy task,

41
00:01:52,910 --> 00:01:55,820
‫which is now running in the background.

42
00:01:55,820 --> 00:01:59,520
‫So what this means is that we can effectively defer

43
00:01:59,520 --> 00:02:01,620
‫or reaction into the future

44
00:02:01,620 --> 00:02:04,530
‫in order to make the code non-blocking

45
00:02:04,530 --> 00:02:07,676
‫and this is, of course, much better.

46
00:02:07,676 --> 00:02:09,287
‫Makes sense?

47
00:02:09,287 --> 00:02:12,203
‫So, in this example, we use the asynchronous

48
00:02:12,203 --> 00:02:16,390
‫readFile function, which accepts a callback function.

49
00:02:16,390 --> 00:02:19,120
‫This will start reading the file in the background

50
00:02:19,120 --> 00:02:22,360
‫and then, immediately move on to the next statement,

51
00:02:22,360 --> 00:02:25,830
‫printing to the console the string-reading file.

52
00:02:25,830 --> 00:02:30,530
‫So, again, you see, we are not blocking the execution here.

53
00:02:30,530 --> 00:02:33,860
‫Then, when the file is finally completely read,

54
00:02:33,860 --> 00:02:35,870
‫the callback function will be called,

55
00:02:35,870 --> 00:02:38,100
‫and so, the data that was read

56
00:02:38,100 --> 00:02:40,270
‫will then be printed to the console.

57
00:02:40,270 --> 00:02:41,890
‫So that's quite different

58
00:02:41,890 --> 00:02:43,893
‫from the synchronous version, isn't it?

59
00:02:44,870 --> 00:02:46,710
‫Now, the question here is,

60
00:02:46,710 --> 00:02:49,490
‫why does is actually have to be this way?

61
00:02:49,490 --> 00:02:53,940
‫What's the problem with blocking code execution in Node.js?

62
00:02:53,940 --> 00:02:57,030
‫Or, in other words, why do we actually use callback

63
00:02:57,030 --> 00:02:59,770
‫so many times in Node.js?

64
00:02:59,770 --> 00:03:01,523
‫Well, let's find out.

65
00:03:03,110 --> 00:03:05,930
‫And in order to understand these questions,

66
00:03:05,930 --> 00:03:08,220
‫the first thing that we need to understand

67
00:03:08,220 --> 00:03:11,260
‫is the fact that a Node.js process,

68
00:03:11,260 --> 00:03:13,760
‫which is where our application is running,

69
00:03:13,760 --> 00:03:16,410
‫there's only one single thread.

70
00:03:16,410 --> 00:03:19,720
‫And the thread is just like a set of instructions

71
00:03:19,720 --> 00:03:22,200
‫that is run in the computer's CPU.

72
00:03:22,200 --> 00:03:25,200
‫So basically, the thread is where our code

73
00:03:25,200 --> 00:03:29,270
‫is actually executed in a machine's processor.

74
00:03:29,270 --> 00:03:33,120
‫So, remember, Node.js is basically single-threaded

75
00:03:33,120 --> 00:03:36,980
‫and so, for each application, there's only one thread.

76
00:03:36,980 --> 00:03:40,300
‫That's just the way Node.js was designed.

77
00:03:40,300 --> 00:03:43,050
‫Now, what that means is that all the users

78
00:03:43,050 --> 00:03:46,960
‫accessing your application are all using the same thread,

79
00:03:46,960 --> 00:03:50,040
‫so, basically, accessing the same thread.

80
00:03:50,040 --> 00:03:53,410
‫And so, whenever they're interacting with the application,

81
00:03:53,410 --> 00:03:55,860
‫the code that is run for each user

82
00:03:55,860 --> 00:03:59,810
‫will be executed all in the same thread at the same place

83
00:03:59,810 --> 00:04:02,490
‫in the computer running the application.

84
00:04:02,490 --> 00:04:04,900
‫And that is true no matter if you have

85
00:04:04,900 --> 00:04:09,900
‫five users, like in this diagram, or 5,000 or 5 million.

86
00:04:10,610 --> 00:04:12,080
‫All right?

87
00:04:12,080 --> 00:04:15,310
‫Now, what this also means is that when one user

88
00:04:15,310 --> 00:04:17,960
‫locks the single thread with synchronous code,

89
00:04:17,960 --> 00:04:19,640
‫like we just saw before,

90
00:04:19,640 --> 00:04:22,280
‫then all other users will have to wait

91
00:04:22,280 --> 00:04:24,680
‫for that execution to finish.

92
00:04:24,680 --> 00:04:27,010
‫And that might not be a huge problem

93
00:04:27,010 --> 00:04:29,800
‫if you have like five users,

94
00:04:29,800 --> 00:04:33,350
‫but it definitely will for thousands or even millions

95
00:04:33,350 --> 00:04:35,393
‫of users at the same time.

96
00:04:36,440 --> 00:04:39,830
‫So, imagine there's a user accessing your application

97
00:04:39,830 --> 00:04:43,280
‫and there's a huge synchronous file read in your code

98
00:04:43,280 --> 00:04:46,630
‫that will take like one second to load.

99
00:04:46,630 --> 00:04:49,920
‫This will mean, of course, that for that one second,

100
00:04:49,920 --> 00:04:52,370
‫all other users will have to wait

101
00:04:52,370 --> 00:04:57,370
‫because the entire execution is blocked for that one second.

102
00:04:57,490 --> 00:05:00,680
‫So if those other users want to do some simple tasks,

103
00:05:00,680 --> 00:05:02,940
‫like logging into your application

104
00:05:02,940 --> 00:05:06,900
‫or just requesting some data, they won't be able to do so.

105
00:05:06,900 --> 00:05:11,150
‫They will have to wait until the file is finished reading.

106
00:05:11,150 --> 00:05:15,130
‫Only when that happens they will finally be able to perform

107
00:05:15,130 --> 00:05:18,113
‫the simpler tasks, one after another.

108
00:05:19,260 --> 00:05:23,290
‫Now, please note, that this is a very oversimplified version

109
00:05:23,290 --> 00:05:27,010
‫of what really happens behind the scenes of Node.js,

110
00:05:27,010 --> 00:05:29,880
‫which is why we will come back to all of this

111
00:05:29,880 --> 00:05:33,760
‫in the next section and get an even deeper understanding

112
00:05:33,760 --> 00:05:38,090
‫of how Node.js handles asynchronous code under the hood.

113
00:05:38,090 --> 00:05:39,370
‫But at this point,

114
00:05:39,370 --> 00:05:42,170
‫this is enough for you to understand the concept.

115
00:05:42,170 --> 00:05:44,560
‫It's better to go step-by-step here

116
00:05:44,560 --> 00:05:46,520
‫and not make it too confusing

117
00:05:46,520 --> 00:05:49,220
‫right from the beginning, okay?

118
00:05:49,220 --> 00:05:51,660
‫Anyway, this is how the situation

119
00:05:51,660 --> 00:05:54,620
‫would play out with synchronous blocking code,

120
00:05:54,620 --> 00:05:58,460
‫which is obviously a terrible experience for your users.

121
00:05:58,460 --> 00:06:01,180
‫And so, it's really your job as a developer

122
00:06:01,180 --> 00:06:03,260
‫to avoid these kinds of situations

123
00:06:03,260 --> 00:06:05,113
‫by using asynchronous code.

124
00:06:07,150 --> 00:06:10,180
‫So, for the same situation, we should, of course,

125
00:06:10,180 --> 00:06:12,780
‫use the asynchronous file read function,

126
00:06:12,780 --> 00:06:15,190
‫which instead of blocking the single thread,

127
00:06:15,190 --> 00:06:17,700
‫does the heavy work in the background,

128
00:06:17,700 --> 00:06:20,170
‫where it basically stays until it's finished

129
00:06:20,170 --> 00:06:22,700
‫reading the data from the file.

130
00:06:22,700 --> 00:06:25,950
‫Of course, we then also register a callback function

131
00:06:25,950 --> 00:06:29,490
‫to be called once the data is available.

132
00:06:29,490 --> 00:06:32,130
‫And in this scenario, all the other users

133
00:06:32,130 --> 00:06:35,100
‫can then perform their tasks in a single thread,

134
00:06:35,100 --> 00:06:38,710
‫one after another, while the file is still being read

135
00:06:38,710 --> 00:06:40,390
‫in the background.

136
00:06:40,390 --> 00:06:43,870
‫Now, once the data is read, our callback function will,

137
00:06:43,870 --> 00:06:46,240
‫of course, get called to be executed

138
00:06:46,240 --> 00:06:51,240
‫in the main single thread in order to process the read data.

139
00:06:51,380 --> 00:06:52,460
‫And that's it.

140
00:06:52,460 --> 00:06:54,720
‫That's an overview of how Node.js

141
00:06:54,720 --> 00:06:58,000
‫handles asynchronous behavior in order to implement

142
00:06:58,000 --> 00:07:00,850
‫the non-blocking I/O model that we talked about

143
00:07:00,850 --> 00:07:03,670
‫in the intro lecture, all right?

144
00:07:03,670 --> 00:07:07,240
‫And I/O simply stands for input-output,

145
00:07:07,240 --> 00:07:10,810
‫which is basically stuff like accessing the file system

146
00:07:10,810 --> 00:07:13,500
‫and handling network requests.

147
00:07:13,500 --> 00:07:16,470
‫This is actually the whole reason why Node.js

148
00:07:16,470 --> 00:07:18,830
‫is completely designed around callbacks,

149
00:07:18,830 --> 00:07:21,190
‫as you will see throughout the course.

150
00:07:21,190 --> 00:07:24,090
‫In other programming languages, like PHP,

151
00:07:24,090 --> 00:07:27,260
‫it works very differently because you get, basically,

152
00:07:27,260 --> 00:07:29,640
‫one new thread for each new user,

153
00:07:29,640 --> 00:07:32,020
‫which is a completely different paradigm

154
00:07:32,020 --> 00:07:34,600
‫and really works completely different.

155
00:07:34,600 --> 00:07:37,620
‫But the creator of Node.js found this model

156
00:07:37,620 --> 00:07:40,660
‫to be the best solution for building highly performant

157
00:07:40,660 --> 00:07:42,980
‫and scalable web applications.

158
00:07:42,980 --> 00:07:46,810
‫Now, just as a final note here, it's important to know that,

159
00:07:46,810 --> 00:07:48,830
‫when we use callbacks in our code,

160
00:07:48,830 --> 00:07:53,380
‫that doesn't automatically make it asynchronous, all right?

161
00:07:53,380 --> 00:07:56,520
‫So, passing functions around into other functions

162
00:07:56,520 --> 00:07:58,780
‫is quite common in JavaScript,

163
00:07:58,780 --> 00:08:01,830
‫but of course, again, that doesn't make them

164
00:08:01,830 --> 00:08:05,110
‫asynchronous automatically, okay?

165
00:08:05,110 --> 00:08:09,150
‫It only works this way for some functions in the Node API,

166
00:08:09,150 --> 00:08:11,210
‫such as the readFile function

167
00:08:11,210 --> 00:08:14,823
‫and many, many more, as people explore in the future.

168
00:08:16,610 --> 00:08:18,500
‫And now, just to finish,

169
00:08:18,500 --> 00:08:21,200
‫since we're talking about asynchronous code here,

170
00:08:21,200 --> 00:08:24,630
‫just one last note about callback functions.

171
00:08:24,630 --> 00:08:27,670
‫So, this callback model that we just discussed,

172
00:08:27,670 --> 00:08:29,370
‫where one function is called

173
00:08:29,370 --> 00:08:32,300
‫once the one before has finished it's work,

174
00:08:32,300 --> 00:08:36,970
‫can quickly lead to some hard to read and unmanageable code.

175
00:08:36,970 --> 00:08:39,830
‫Just take this example where the second file read

176
00:08:39,830 --> 00:08:41,870
‫depends on the first one,

177
00:08:41,870 --> 00:08:44,800
‫then, the third file read depends on the second one,

178
00:08:44,800 --> 00:08:47,560
‫and finally, we want to use the final data

179
00:08:47,560 --> 00:08:49,700
‫to write a file as a result.

180
00:08:49,700 --> 00:08:52,690
‫That looks quite confusing, right?

181
00:08:52,690 --> 00:08:54,950
‫I mean, it's gonna work just fine,

182
00:08:54,950 --> 00:08:57,330
‫but it's just hard to reason about

183
00:08:57,330 --> 00:09:00,110
‫and that is just with four levels deep.

184
00:09:00,110 --> 00:09:02,980
‫Imagine you had like 10 or 20 levels,

185
00:09:02,980 --> 00:09:05,850
‫which is actually not that uncommon.

186
00:09:05,850 --> 00:09:09,440
‫Anyway, this is what we call the callback hell.

187
00:09:09,440 --> 00:09:11,370
‫It's such a common problem,

188
00:09:11,370 --> 00:09:13,780
‫that it already got its own name.

189
00:09:13,780 --> 00:09:16,920
‫And do you notice this triangular shape here?

190
00:09:16,920 --> 00:09:20,840
‫That's a very clear sign that you're in callback hell.

191
00:09:20,840 --> 00:09:24,350
‫Now, how do we actually escape callback hell?

192
00:09:24,350 --> 00:09:27,600
‫Well, we can use more advanced tools for handling

193
00:09:27,600 --> 00:09:30,730
‫asynchronous code, like ES6 promises

194
00:09:30,730 --> 00:09:34,150
‫or even better, ES8 async/await.

195
00:09:34,150 --> 00:09:36,320
‫Now, the model that we just talked about

196
00:09:36,320 --> 00:09:37,890
‫will still be the same.

197
00:09:37,890 --> 00:09:39,960
‫We just have more elegant ways

198
00:09:39,960 --> 00:09:43,370
‫of dealing with the code itself and writing it.

199
00:09:43,370 --> 00:09:45,830
‫And there is a whole optional section

200
00:09:45,830 --> 00:09:50,090
‫of it later in the course on promises and also, async/await,

201
00:09:50,090 --> 00:09:52,590
‫so in case you're not familiar with them.

202
00:09:52,590 --> 00:09:55,140
‫But for now, we will keep using callbacks

203
00:09:55,140 --> 00:09:57,900
‫because that is what Node originally used

204
00:09:57,900 --> 00:10:00,100
‫and was designed around.

205
00:10:00,100 --> 00:10:02,030
‫And now, with that being said,

206
00:10:02,030 --> 00:10:05,240
‫let's move on and use this asynchronous model

207
00:10:05,240 --> 00:10:07,233
‫in practice for the first time.

