NodeJS的学习笔记流模块
流是一个抽象的接口,通过节点中的许多对象来实现。例如,一个HTTP服务器的请求是一个流,和标准输出流。流是可读,可写或两者。
与流的最早接触始于早期UNIX,几十年的实践证明流思想可以是大量系统的非常简单的开发。
在Unix中,流是通过| 的实现,节点,作为一个内置的流模块,采用了许多核心模块和三方模块。
与UNIX一样,节点流的主要操作是管道(),用户可以使用反压力机制来控制读写平衡。
流可以为开发人员提供一个可重用的统一接口,通过抽象流接口控制流之间的读写平衡。
TCP连接既可读又可写,而HTTP连接则不同。HTTP请求对象是可读的,而HTTP响应对象是可写的。
流的传输过程默认是以缓冲的形式传输的,除非您为他设置其他编码形式,下面是一个示例:
复制代码代码如下所示:
var http =需要('http');
VaR服务器= http.createserver(功能(REQ,RES){
res.writeheader(200,{ 'content-type:中/平原});
res.end(你好,大熊!;
});
(8888)server.listen;
console.log(HTTP服务器运行在8888端口上…);
运行后,会有一个随机码,因为没有设置指定的字符集,例如UTF-8。
只是修改它。
复制代码代码如下所示:
var http =需要('http');
VaR服务器= http.createserver(功能(REQ,RES){
res.writeheader(200,{
内容类型:中/普通字符集= UTF-8的字符集= UTF-8; / /添加
});
res.end(你好,大熊!;
});
(8888)server.listen;
console.log(HTTP服务器运行在8888端口上…);
运行结果:
为什么要使用流
节点中的I/O是异步的,因此对磁盘和网络的读写需要通过回调函数读取数据。下面是一个文件下载示例
上面的代码:
复制代码代码如下所示:
var http =需要('http');
VaR FS =需要('fs);
VaR服务器= http.createserver(功能(REQ,RES){
fs.readfile(__dirname +/数据.txt功能(呃,数据){
res.end(数据);
});
});
(8888)server.listen;
代码可以实现所需的功能,但是服务需要在发送文件数据之前将整个文件数据缓存到内存中,如果文件非常好。
大量的并发会浪费大量的内存,因为用户需要等到整个文件缓存到内存才能接受文件数据,这会导致什么原因呢
用户体验是很坏的。但是很好(REQ,RES)这两个参数均流,所以我们可以使用fs.createreadstream()而不是fs.readfile(如下):
复制代码代码如下所示:
var http =需要('http');
VaR FS =需要('fs);
VaR服务器= http.createserver(功能(REQ,RES){
无功流= fs.createreadstream(__dirname +/数据.txt);
Stream.pipe(RES);
});
(8888)server.listen;
的。管()方法听the'data'and'end事件fs.createreadstream()这样的数据。txt文件不需要缓存。
一个文件,当客户机连接完成时,数据块可以立即发送给客户机。另一个使用管道()的优点是它可以作为一个客户来解决。
读写不平衡是由大的端延迟引起的。
流有五种基本类型:可读的、可写的、转换的、双工的和经典的(使用特定的API)。
二、实例介绍
我们需要使用数据流的数据时,没有安装过的记忆,或当读取和处理更efficient.nodejs提供操作的数据流通过各种流。
作为大文件复制程序的一个例子,我们可以为数据源创建只读数据流。示例如下:
复制代码代码如下所示:
VaR RS = fs.createreadstream(路径);
Rs.on(数据功能(块){
DoSomething(块); / /任何细节,他的发挥
});
Rs.on(函数(){(){
清理();
});
代码中的数据事件不断引发,无论做函数处理。代码可以继续修改来解决这个问题。
复制代码代码如下所示:
VaR RS = fs.createreadstream(SRC);
Rs.on(数据功能(块){
Rs.pause();
DoSomething(块,函数(){(){
Rs.resume();
});
});
Rs.on(函数(){(){
清理();
});
回调是添加到一些功能,所以我们可以暂停读取数据前处理数据并继续处理后的数据读取数据。
此外,我们还可以为数据目标创建一个只写数据流,如下所示:
复制代码代码如下所示:
VaR RS = fs.createreadstream(SRC);
VaR WS = fs.createwritestream(DST);
Rs.on(数据功能(块){
ws.write(块);
});
Rs.on(函数(){(){
Ws.end();
});
做一些改变来写入数据后,只写的数据流,上面的代码看起来像一个文件复制程序,但上面的代码中存在的上述问题,如果写的速度跟不上阅读速度,只是写数据流缓存内会破产。我们可以根据写的返回值。确定输入的数据被写入到目标,或暂时放在缓存中,并根据漏事件来确定什么时间只写数据流缓存中的数据写入到目标,可以传递给下一个写入数据。因此,代码如下:
复制代码代码如下所示:
VaR RS = fs.createreadstream(SRC);
VaR WS = fs.createwritestream(DST);
Rs.on(数据功能(块){
如果(ws.write(块)= false){
Rs.pause();
}
});
Rs.on(函数(){(){
Ws.end();
});
Ws.on('drain,函数(){(){
Rs.resume();
});
最后,数据流从只读数据流只有实现了数据流、防爆仓库控制。因为有很多应用场景,比如大文件复制程序上,Nodejs直接提供。管的方法来做这件事,和其内部的实现类似于上面的代码。
下面是一个比较完整的复制文件的过程:
复制代码代码如下所示:
VaR FS =需要('fs),
路径=需要('path),
= process.stdout;
var文件路径= / /只大熊MKV的BB;
无功readstream = fs.createreadstream(路径);
无功writestream = fs.createwritestream(MKV文件。);
var属性= fs.statsync(路径);
VaR stat.size规模=;
无功passedlength = 0;
无功lastsize = 0;
VaR StartTime = Date.now();
readstream.on(数据功能(块){
passedlength = chunk.length;
如果(writestream.write(块)= false){
readstream.pause();
}
});
readstream.on(最终,函数(){(){
WriteStream.end();
});
writestream.on('drain,函数(){(){
ReadStream.resume();
});
setTimeout(函数(){)
无功率= math.ceil((passedlength /规模)×100);
无功大小= math.ceil(passedlength / 1000000);
不同尺寸lastsize var =;
lastsize =尺寸;
out.clearline();
(0)out.cursorto;
out.write('completed +规模+ 'mb + % +,+速度:diff * 2 + 'mb / S);
如果(passedlength < TotalSize){
setTimeout(,500);
{人}
VaR结果= Date.now();
console.log();
console.log('shared:+(结束时间-开始时间)/ 1000 +秒。);
}
},500);
我们可以把上面的代码保存为拷贝并测试它。我们添加了一个递归的setTimeout(或直接使用setInterval)使观众。
一旦观察到每隔500ms,进步一次完成,以及完成的尺寸、比例和复制速度写入控制台。复制完成后,计算所花费的总时间。
三,总结
(1)理解流的概念。
(2)熟练使用api相关的流
(3)注意控件的细节,如:大文件的拷贝,利用分段数据的形式进行分段处理。
(4)管道的使用
(5)再次强调了一个概念:TCP连接既可读又可写,而HTTP连接则不同。HTTP请求对象是可读的,而HTTP响应对象是可写的。