Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:01,270 --> 00:00:04,633
All right, now lets actually work with streams.
2
00:00:06,140 --> 00:00:09,363
And again, starting by creating a new file.
3
00:00:13,160 --> 00:00:16,370
All right. Now lets say that for some reason in
4
00:00:16,370 --> 00:00:20,440
our application, we need to read a large text file from
5
00:00:20,440 --> 00:00:23,800
the file system, and then send it to the client.
6
00:00:23,800 --> 00:00:25,640
So how would we do that?
7
00:00:25,640 --> 00:00:28,650
Well there are multiple ways and we're going to explore
8
00:00:28,650 --> 00:00:31,630
a few of them starting with the most basic one
9
00:00:31,630 --> 00:00:35,320
and moving all the way to the best way of doing this.
10
00:00:35,320 --> 00:00:39,090
Okay, so the first thing is to require the file system
11
00:00:39,090 --> 00:00:43,220
package just like before, and also the HTTP module.
12
00:00:46,810 --> 00:00:49,600
Let me now show you a nice trick,
13
00:00:49,600 --> 00:00:52,183
so lets actually create a server like this.
14
00:00:53,770 --> 00:00:58,770
So, require the HTTP package, and then from here we can
15
00:00:59,530 --> 00:01:04,530
right away call createServer. So just like this.
16
00:01:05,550 --> 00:01:09,720
Okay, so the result of requiring HTTP, is the
17
00:01:09,720 --> 00:01:13,700
HTTP object and on there we can then use createServer.
18
00:01:13,700 --> 00:01:16,690
Just like this, and then save it into a variable.
19
00:01:16,690 --> 00:01:19,620
So that is yet another way of creating a new server
20
00:01:19,620 --> 00:01:21,943
with writing even a bit less code.
21
00:01:24,530 --> 00:01:29,530
Okay and so just like before lets now list to the request
22
00:01:29,970 --> 00:01:34,970
event, and specify our callback here.
23
00:01:38,550 --> 00:01:41,190
So, the first solution that we're going to use is the
24
00:01:41,190 --> 00:01:43,600
easiest and most straight-forward one.
25
00:01:43,600 --> 00:01:46,690
Which is to simply read the file into a variable,
26
00:01:46,690 --> 00:01:49,350
and then once that's done, send it to the client
27
00:01:49,350 --> 00:01:52,020
in the way that we already know how to do it.
28
00:01:52,020 --> 00:01:54,660
So that one's very simple, and let me write a comment
29
00:01:54,660 --> 00:01:58,410
here for that. So solution one, and so
30
00:01:58,410 --> 00:02:03,410
fs.readFile then our test file again.
31
00:02:09,100 --> 00:02:12,720
And then once that's ready, we call our callback function
32
00:02:12,720 --> 00:02:15,270
in which we have access to the data.
33
00:02:15,270 --> 00:02:17,703
But first lets handle the error.
34
00:02:20,930 --> 00:02:24,880
So for example in case that the file does not exist,
35
00:02:24,880 --> 00:02:28,250
and in that case we simply log the error to the console.
36
00:02:28,250 --> 00:02:32,340
But otherwise, we simply send this data back to the client.
37
00:02:32,340 --> 00:02:35,280
So we use the response object just like we did before
38
00:02:35,280 --> 00:02:40,280
many times, and then .end and the data.
39
00:02:40,610 --> 00:02:44,010
So, give it a save, and so that is the first
40
00:02:44,010 --> 00:02:46,363
and the simplest solution, right?
41
00:02:47,450 --> 00:02:50,460
But before we can test this, we need to actually also
42
00:02:51,470 --> 00:02:55,433
start a sever, right? So we use listen to do that.
43
00:02:56,770 --> 00:03:01,603
And the port, the same one as before, then localhost
44
00:03:03,440 --> 00:03:05,253
and our callback function.
45
00:03:12,960 --> 00:03:15,353
Okay, so lets see if this actually works.
46
00:03:24,080 --> 00:03:27,880
And of course not, because I actually didn't even start
47
00:03:27,880 --> 00:03:29,023
the application.
48
00:03:31,260 --> 00:03:33,810
So now it says listening, and now lets see
49
00:03:33,810 --> 00:03:34,853
what happens here.
50
00:03:35,730 --> 00:03:39,565
And here we go. So this file is huge, it has
51
00:03:39,565 --> 00:03:42,960
Node.js is the best written in it like 10000 times
52
00:03:42,960 --> 00:03:46,080
or something, and so it takes a lot of time
53
00:03:46,080 --> 00:03:49,760
until it loads entirely. And we're not really interested in
54
00:03:49,760 --> 00:03:53,010
loading everything, so lets stop this here,
55
00:03:53,010 --> 00:03:56,430
and go back to our code. So this works just fine, the
56
00:03:56,430 --> 00:03:59,480
solution one that we have here in this case,
57
00:03:59,480 --> 00:04:01,970
but the problem is that with this solution,
58
00:04:01,970 --> 00:04:04,660
node will actually have to load the entire file
59
00:04:04,660 --> 00:04:07,610
into memory, because only after that's ready,
60
00:04:07,610 --> 00:04:10,890
it can then send that data. Now this is a problem
61
00:04:10,890 --> 00:04:14,120
when the file is big, and also when there are a ton
62
00:04:14,120 --> 00:04:17,240
of requests hitting your server. Because the node process
63
00:04:17,240 --> 00:04:21,464
will very quickly run out of resources and your app will
64
00:04:21,464 --> 00:04:25,740
quit working, everything will crash, and your users
65
00:04:25,740 --> 00:04:28,940
will not be happy believe me. So this solution here
66
00:04:28,940 --> 00:04:31,500
does work when we're just creating something small
67
00:04:31,500 --> 00:04:33,990
locally for just ourselves, for example.
68
00:04:33,990 --> 00:04:37,030
But in a production-ready application, you cannot use
69
00:04:37,030 --> 00:04:41,270
a piece of code like this. Okay? So lets move on to
70
00:04:41,270 --> 00:04:44,070
our second solution. And in that solution,
71
00:04:44,070 --> 00:04:46,933
we will actually use streams.
72
00:04:48,760 --> 00:04:52,420
Okay, so lets comment out this part,
73
00:04:52,420 --> 00:04:55,890
and move on to solution number two.
74
00:04:55,890 --> 00:04:58,270
And the idea here is that we actually don't really
75
00:04:58,270 --> 00:05:03,000
need to read this data from the file into a variable, right?
76
00:05:03,000 --> 00:05:05,860
We don't need this variable. So instead of reading
77
00:05:05,860 --> 00:05:09,310
the data into a variable, and having to store that variable
78
00:05:09,310 --> 00:05:12,710
into memory, we will just create a readable stream.
79
00:05:12,710 --> 00:05:15,490
Then as we receive each chunk of data,
80
00:05:15,490 --> 00:05:17,920
we send it to the client as a response
81
00:05:17,920 --> 00:05:20,440
which is a writable stream remember.
82
00:05:20,440 --> 00:05:22,963
So let me now show you how we can use streams.
83
00:05:24,570 --> 00:05:28,823
So we create a variable, lets call it readable here,
84
00:05:30,025 --> 00:05:33,437
and then from the file system again, we use createReadStream
85
00:05:39,450 --> 00:05:44,450
Then this of course small. And now the name of the file
86
00:05:44,820 --> 00:05:49,820
that we're trying to read. So that is again, test-file.txt.
87
00:05:50,580 --> 00:05:54,130
Okay, perfect. So this now creates a stream from
88
00:05:54,130 --> 00:05:57,090
the data that is in this text file, which we can then
89
00:05:57,090 --> 00:06:00,540
consume piece by piece. So chunk by chunk.
90
00:06:00,540 --> 00:06:03,350
And how do we do that? Well, remember from the last
91
00:06:03,350 --> 00:06:06,600
lecture, that each time there is a new piece of data
92
00:06:06,600 --> 00:06:10,020
that we can consume, a readable stream emits the
93
00:06:10,020 --> 00:06:13,070
data event. Okay, and so we can listen to that,
94
00:06:13,070 --> 00:06:15,313
just like we learned in the events lecture.
95
00:06:17,220 --> 00:06:22,220
So readable.on, data, and then our callback function.
96
00:06:23,690 --> 00:06:26,910
And in our callback function, we have access to
97
00:06:26,910 --> 00:06:28,993
that piece of data, so to that chunk.
98
00:06:30,160 --> 00:06:32,660
Let me call it chunk here in our callback function
99
00:06:33,540 --> 00:06:37,100
and so now we can handle this piece of data.
100
00:06:37,100 --> 00:06:39,060
And what we're going to do with this piece of data,
101
00:06:39,060 --> 00:06:42,010
with this chunk, is to actually write it to a
102
00:06:42,010 --> 00:06:45,210
writable stream, which is the response.
103
00:06:45,210 --> 00:06:50,210
So, res.write, this chunk. Okay?
104
00:06:51,250 --> 00:06:54,080
So again remember that this response is a
105
00:06:54,080 --> 00:06:57,760
writable stream. So just as I mentioned in the previous
106
00:06:57,760 --> 00:07:01,540
video, right? And so we can now use the write method
107
00:07:01,540 --> 00:07:06,110
to send every single piece of data into that stream.
108
00:07:06,110 --> 00:07:08,920
Okay, and with this effectively we're streaming
109
00:07:08,920 --> 00:07:12,230
the content from the file right to the client.
110
00:07:12,230 --> 00:07:14,300
Okay, you understand the difference?
111
00:07:14,300 --> 00:07:17,710
So before, we write everything at once into a variable,
112
00:07:17,710 --> 00:07:21,000
and once that was ready, we then sent that entire piece
113
00:07:21,000 --> 00:07:23,927
of data back to the client. But in this situation,
114
00:07:23,927 --> 00:07:26,370
with the stream, it is different.
115
00:07:26,370 --> 00:07:29,730
We're effectively streaming the file, so we read one piece
116
00:07:29,730 --> 00:07:32,670
of the file, and as soon as that's available,
117
00:07:32,670 --> 00:07:37,440
we send it right to the client, using the write method
118
00:07:37,440 --> 00:07:40,990
of the respond stream. Then when the next piece is available
119
00:07:40,990 --> 00:07:44,290
then that piece will be sent, and all the way until
120
00:07:44,290 --> 00:07:48,390
the entire file is read and streamed to the client.
121
00:07:48,390 --> 00:07:51,650
Okay, so now just to finish, we also have to handle
122
00:07:51,650 --> 00:07:54,680
the event when all the data is read.
123
00:07:54,680 --> 00:07:57,430
So when the stream is basically finished reading the data
124
00:07:57,430 --> 00:07:58,263
from the file.
125
00:07:59,580 --> 00:08:03,113
So on that case, the end event will be emitted,
126
00:08:05,810 --> 00:08:10,040
and so as soon as that happens what we're going to do
127
00:08:10,040 --> 00:08:15,040
is to do res.end, okay? And we used this one before,
128
00:08:16,430 --> 00:08:21,220
so calling end on the response, we did that before, right?
129
00:08:21,220 --> 00:08:25,000
And now, it makes actually more sense, because again,
130
00:08:25,000 --> 00:08:28,540
the response is also a stream, and the end method
131
00:08:28,540 --> 00:08:31,820
signals that no more data will be written to this
132
00:08:31,820 --> 00:08:34,090
writable stream, okay?
133
00:08:34,090 --> 00:08:39,080
So up here all we did was actually use res.end with the
134
00:08:39,080 --> 00:08:41,970
data in it. So we did no streaming, all we did was
135
00:08:41,970 --> 00:08:44,490
in the end to send some data.
136
00:08:44,490 --> 00:08:46,470
Now in this case, we're not passing anything
137
00:08:46,470 --> 00:08:50,000
into this end method, because we already sent all the data
138
00:08:50,000 --> 00:08:52,930
using res.write, chunk by chunk,
139
00:08:52,930 --> 00:08:55,550
and so when the readable stream is finished reading
140
00:08:55,550 --> 00:08:59,220
its file, well all we have to do is to then signal
141
00:08:59,220 --> 00:09:03,330
that we're ready using res.end like this, okay?
142
00:09:03,330 --> 00:09:07,910
So we always need to use this data and this end event here
143
00:09:07,910 --> 00:09:11,160
one after another like this. Because otherwise,
144
00:09:11,160 --> 00:09:14,030
the response will actually never really be sent
145
00:09:14,030 --> 00:09:17,340
to the client. Okay, so without this piece here,
146
00:09:17,340 --> 00:09:20,230
this entire solution would not really work, okay?
147
00:09:20,230 --> 00:09:25,000
So lets now close this one, start again,
148
00:09:25,000 --> 00:09:30,000
and read again, and so you see that its actually working
149
00:09:30,880 --> 00:09:35,670
again, okay? Now this time without the problems we had
150
00:09:35,670 --> 00:09:39,400
with the first solution. Lets stop this here, and go back
151
00:09:39,400 --> 00:09:41,770
to our code, because I want to show you now,
152
00:09:41,770 --> 00:09:44,260
that there is another event that we can listen to
153
00:09:44,260 --> 00:09:47,403
on a readable stream, which is the error event.
154
00:09:49,240 --> 00:09:54,240
So readable.on('error') and in this callback function
155
00:09:55,000 --> 00:09:57,733
we have access to the error object.
156
00:09:58,810 --> 00:10:03,683
Okay so in this case we will log this error to the console,
157
00:10:05,970 --> 00:10:10,593
and then send the result of file not found.
158
00:10:14,400 --> 00:10:17,283
And we can also set the status code to an error,
159
00:10:20,160 --> 00:10:23,772
so 500 for example. So usually it's automatically set to 200
160
00:10:23,772 --> 00:10:28,020
which means okay, but in this case we have a server error,
161
00:10:28,020 --> 00:10:31,420
which means that we want to send back the code 500.
162
00:10:31,420 --> 00:10:36,213
All right, so lets now...
163
00:10:37,390 --> 00:10:39,313
Actually I need to quit this again.
164
00:10:45,520 --> 00:10:46,970
So lets see what happens now.
165
00:10:53,001 --> 00:10:54,870
Oh we already have an error right here,
166
00:10:54,870 --> 00:10:57,790
res.status is not a function. And yeah,
167
00:10:57,790 --> 00:11:00,872
actually its statusCode. So this is the way that
168
00:11:00,872 --> 00:11:05,100
you write it in express, so I'm already used to writing
169
00:11:05,100 --> 00:11:10,100
express so much, so express is a node.js framework
170
00:11:10,370 --> 00:11:12,150
which we're going to use in the rest of the course
171
00:11:12,150 --> 00:11:15,060
and in express you do it like this, and so that was
172
00:11:15,060 --> 00:11:18,420
the problem. So I'm already a bit too used
173
00:11:18,420 --> 00:11:19,673
to writing express.
174
00:11:22,460 --> 00:11:26,470
So lets go back, and yeah so now we see file not found,
175
00:11:26,470 --> 00:11:31,090
and if we open up the dev tools, you see our 500 error code
176
00:11:31,090 --> 00:11:34,823
that we just sent before, and if we go to our network tab,
177
00:11:36,440 --> 00:11:39,840
lets try that again, you have the status code here as well.
178
00:11:39,840 --> 00:11:43,990
So just like we saw in one of the previous videos in another
179
00:11:43,990 --> 00:11:47,130
section actually. So this is how we can inspect this
180
00:11:47,130 --> 00:11:49,343
kind of stuff in the network tab.
181
00:11:52,530 --> 00:11:57,343
All right, so lets fix it here, give it a save,
182
00:11:58,300 --> 00:12:03,300
and okay so this again works just perfectly
183
00:12:03,550 --> 00:12:06,240
but there still is a problem with this approach
184
00:12:06,240 --> 00:12:09,360
that I just showed you. And the problem is that our
185
00:12:09,360 --> 00:12:12,240
readable stream, so the one that we're using to read
186
00:12:12,240 --> 00:12:16,100
the file from the disk, is much much faster than actually
187
00:12:16,100 --> 00:12:19,310
sending the result with the response writable stream
188
00:12:19,310 --> 00:12:22,910
over the network. And this will overwhelm the response
189
00:12:22,910 --> 00:12:27,360
stream, which cannot handle all this incoming data so fast.
190
00:12:27,360 --> 00:12:29,920
And this problem is called backpressure.
191
00:12:29,920 --> 00:12:33,510
And it's a real problem that can happen in real situations.
192
00:12:33,510 --> 00:12:37,140
So in this case, backpressure happens when the response
193
00:12:37,140 --> 00:12:41,130
cannot send the data nearly as fast as it is receiving it
194
00:12:41,130 --> 00:12:43,620
from the file, does that make sense?
195
00:12:43,620 --> 00:12:46,050
So we have to fix that solution,
196
00:12:46,050 --> 00:12:48,793
and come up with an even better one.
197
00:12:50,130 --> 00:12:52,813
And so, we will create solution three,
198
00:12:55,120 --> 00:12:57,527
and that is actually the final one,
199
00:12:57,527 --> 00:13:01,150
Okay? So no more solutions than three.
200
00:13:01,150 --> 00:13:05,000
So the secret here is to actually use that pipe operator
201
00:13:05,000 --> 00:13:07,405
that I mentioned in the last video, okay?
202
00:13:07,405 --> 00:13:12,405
So the pipe operator is available on all readable streams,
203
00:13:12,960 --> 00:13:16,760
and it allows us to pipe the output of a readable stream
204
00:13:16,760 --> 00:13:20,660
right into the input of a writable stream, okay?
205
00:13:20,660 --> 00:13:24,010
And that will then fix the problem of backpressure
206
00:13:24,010 --> 00:13:27,340
because it will automatically handle the speed basically
207
00:13:27,340 --> 00:13:31,260
of the data coming in, and the speed of the data going out.
208
00:13:31,260 --> 00:13:35,603
Okay, so lets actually get our readable stream here.
209
00:13:38,290 --> 00:13:41,290
Okay, so that is our readable stream, and now
210
00:13:41,290 --> 00:13:45,253
all we have to do is to take our readable stream,
211
00:13:46,280 --> 00:13:50,650
use the pipe method on it, and then put in a writable stream
212
00:13:50,650 --> 00:13:53,900
and that is the response. And that's actually it.
213
00:13:53,900 --> 00:13:57,460
That's all we have to do for this solution, okay?
214
00:13:57,460 --> 00:13:59,960
So it always works like this, let me write it out here
215
00:13:59,960 --> 00:14:04,960
as a comment. So we need a readable source basically, okay
216
00:14:06,040 --> 00:14:09,310
so again this is just to explain it to you,
217
00:14:09,310 --> 00:14:12,330
then we can use the pipe on it, and here we will have to put
218
00:14:12,330 --> 00:14:17,010
a writable destination. So this is where our data
219
00:14:17,010 --> 00:14:19,980
comes from, and it has to be a readable stream,
220
00:14:19,980 --> 00:14:24,980
and that data we can then pipe into a writable destination.
221
00:14:25,060 --> 00:14:29,520
So in this case our destination is the response, okay?
222
00:14:29,520 --> 00:14:32,790
Now this stream here can actually be a duplex or a
223
00:14:32,790 --> 00:14:35,790
transform stream as well, but what matters is that
224
00:14:35,790 --> 00:14:38,930
we can write to the stream. And response of course,
225
00:14:38,930 --> 00:14:42,553
is such a stream. So we can of course write to the response
226
00:14:42,553 --> 00:14:45,560
that will be sent to the client, okay?
227
00:14:45,560 --> 00:14:48,890
So the pipe operator automatically solves the problem
228
00:14:48,890 --> 00:14:51,860
of backpressure that we had previously.
229
00:14:51,860 --> 00:14:54,720
And it's also actually a much more elegant and
230
00:14:54,720 --> 00:14:58,000
straight-forward solution. So what we did here before
231
00:14:58,000 --> 00:15:01,020
was just to show you all the ways in which we can
232
00:15:01,020 --> 00:15:05,290
use the stream methods and events in order to create this
233
00:15:05,290 --> 00:15:08,520
kind of solution and of course they have many use cases,
234
00:15:08,520 --> 00:15:12,044
but in a problem like this, the pipe operator is actually
235
00:15:12,044 --> 00:15:16,060
the best solution. Behind the scenes it does something like
236
00:15:16,060 --> 00:15:17,950
this here actually, but again in a
237
00:15:17,950 --> 00:15:20,880
much more straight-forward way for us to write,
238
00:15:20,880 --> 00:15:23,000
because it handles all the stuff internally
239
00:15:23,000 --> 00:15:26,500
behind the scenes. So I believe that pipe here is actually
240
00:15:26,500 --> 00:15:30,370
the easiest way of consuming and writing streams, unless
241
00:15:30,370 --> 00:15:33,410
of course, as I mentioned, we need a more customized
242
00:15:33,410 --> 00:15:36,670
solutions. And then, we have to use these more complicated
243
00:15:36,670 --> 00:15:39,910
tools like these events and methods that
244
00:15:39,910 --> 00:15:43,633
I showed you before. All right, so just to finish,
245
00:15:45,270 --> 00:15:50,270
lets quit the process here, start it again,
246
00:15:50,370 --> 00:15:54,350
and of course, see if it still works, which it does.
247
00:15:54,350 --> 00:15:58,340
And so, our work is done here. So we're finished with this
248
00:15:58,340 --> 00:16:01,343
lecture, and ready to go straight to the next one.
21631
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.