深入学习Node.js中的Stream:从基础到实战


我们今天来学习一下nodejs中的Stream相关知识,我们从以下几个例子开始讲起。

  1. 第一个例子,新建1.js
const fs = require('fs')
const stream = fs.createWriteStream('./big_file.txt')
for (let i = 0; i < 1000000; i++) {
  stream.write(`这是第${i}行内容,我们需要很多很多内容,要不停地写文件啊啊啊啊啊啊回车n`)
}
stream.end()//别忘了关掉
console.log('done')
  • 通过运行上面的这段代码,我们能得到一个10000行的文件
  • 分析
    • 我们通过打开流,多次往里面塞内容,关闭流
    • 最终我们得到一个1mb左右的文件
  1. 什么是Steam流
  • 释义
    • stream是水流,但默认没有水
    • stream.write可以让水流中有水(数据)
    • 每次写的小数据叫做chunk(块)
    • 产生数据的一段叫做source(源头)
    • 得到数据的一段叫做sink(水池)
深入学习Node.js中的Stream:从基础到实战
  1. 第二个例子,没有使用数据流进行读写,新建2.js
const http = require("http")
const fs = require("fs")
const server = http.createServer()
server.on('request', (request, response) => {
  fs.readFile('./big_file.txt', (error, data) => {
    if (error) throw error;
    response.end(data)
    console.log('done')
  })
})
server.listen(8888)
console.log('8888')
  • 直接用浏览器或者chrome访问
  • 分析
    • 用任务管理器看看Node.js内存占用,会很大概100mb,这就是不用流的问题

    • 访问前内存深入学习Node.js中的Stream:从基础到实战

    • 访问后开始读取文件的内存深入学习Node.js中的Stream:从基础到实战

  1. 第三个例子,使用Stream改写第二个例子
const http = require("http")
const fs = require("fs")
const server = http.createServer()
server.on('request', (request, response) => {
  const stream = fs.createReadStream('./big_file.txt')
  stream.pipe(response)
  stream.on('end',()=>console.log('done'))
})
server.listen(8888)
console.log('8888')
  • 分析
    • 内存占用会少很多
深入学习Node.js中的Stream:从基础到实战
  1. 什么是管道(pipe)
  • 释义
    • 两个流可以用一个管道相连,stream1的末尾连接上stream2的开端,只要stream1有数据,就会流到stream2
    • 常用代码
stream1.pipe(stream2)
// 链式操作
a.pipe(b).pipe(c)
// 等价于
a.pipe(b)
b.pipe(c)
深入学习Node.js中的Stream:从基础到实战
  • 管道可以通过事件实现,一般不这么写直接用pipe
// stream1 一有数据就塞给 stream2
stream1.on('data',(chunk)=>{
  stream2.write(chunk)
})
// stream1停了,就停掉stream2
stream1.on('end',()=>s{
  stream2.end()
})
  1. Stream对象的原型、事件
  • 新建4.js
const fs = require('fs')
const s = fs.createReadStream('./big_file.txt')
console.log(s)
  • 运行node --inspect-brk 4.js
  • 打开浏览器进入调试模式,打上断点
  • 可以在控制台看到steam的层级结构,也就是Stream对象的原型链
    • 自身属性(由fs.ReadStream构造)
    • 原型:stream.Readable.prototype
    • 二级原型:stream.Stream.prototype
    • 三级原型:events.EventEmitter.prototype
    • 四级原型:Object.prototype
  • Stream对象都继承了EventEmitter
深入学习Node.js中的Stream:从基础到实战
  • Stream支持的事件和方法
深入学习Node.js中的Stream:从基础到实战
stream.on('data', (chunk)=>{
  console.log(chunk)
  // chunk是一个buffer,就是每次把数据读成二进制的形式放在内存里,没有时间变成字符串,字符串需要编码,这里打出来就是十六进制表示01
  console.log(chunk.toString()) //就可以变成字符串
})
  • 这里特别注意下drain事件,因为面试常考,但是实际开发用的不多。可以参考下面的例子,
  • 简单理解,在处理大量数据或以较慢的速度写入数据的情况下,写入数据可能会超过可写流的缓冲区容量,导致暂时停止写入。drain事件的触发表示缓冲区已经排空,可以继续写入数据了。
const fs = require('fs');
const writableStream = fs.createWriteStream('example.txt');

// 假设这是一个大型数据流
const data = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';

// 当写入的数据量超过缓冲区大小时,write 方法会返回 false
while (!writableStream.write(data)) {
  console.log('缓冲区已满,等待 drain 事件');
  // 在 drain 事件发生后继续写入
}

// 当缓冲区排空时,会触发 drain 事件
writableStream.on('drain', () => {
  console.log('缓冲区已排空,可以继续写入');
});

console.log('数据写入完成');
  1. Stream的分类
  • 有四类
    • 可读流 (Readable),提供从数据源读取数据的流。示例:文件读取流、HTTP 请求流。
const fs = require('fs');
const readableStream = fs.createReadStream('example.txt');
  • 可写流 (Writable),提供向目标写入数据的流。示例:文件写入流、HTTP 响应流。
const fs = require('fs');
const writableStream = fs.createWriteStream('output.txt');
  • 双工流(可读可写双向) (Duplex) ,同时具有读取和写入功能的流。示例:网络套接字、WebSocket。
const net = require('net');
const duplexStream = new net.Socket();
  • 转换流(可读可写变化) (Transform),类似于双工流,但是可以修改或转换数据。示例:数据压缩、加密。
const zlib = require('zlib');
const transformStream = zlib.createGzip();
  1. 可读和可写流的特点
  • 可读(Readable Stream)
    • 可读流有静止态paused和流动态flowing
    • 默认处于paused态
    • 添加data事件监听,它就变为flowing态
    • 删掉data事件监听,它就变为paused态
    • pause()可以将它变为paused
    • resume()可以将它变为flowing
  • 可写(Writeable Stream)
    • 调用stream.end()之后
    • 而且缓冲区数据都已经传给底层系统之后
    • 触发finish事件
    • 表示可以加点水了
    • 调用stream.write(chunk)的时候,可能会得到false
    • false的意思是你写太快了,数据积压了
    • 这个时候我们就不能再write了,要监听drain
    • 等drain事件触发了,我们才能继续write
    • drain流干了事件
    • finish事件

原文始发于微信公众号(前端之乐):深入学习Node.js中的Stream:从基础到实战

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/274572.html

(0)
OriesZhu的头像OriesZhubm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!