Node.js 高级编程之 Stream(我是跟 ChatGPT 学会的)

前言

在做 SSR Stream Render 的时候遇到了 Node.js 的 Stream,但是对其总是一知半解。正好最近 ChatGPT 很火,找他学一学吧,没想到真的把我教会了。PS:文末有跟 ChatGPT 的精彩对话(请忽略我稀烂的英语)。

为什么需要 Stream

首先我们通过一个简单的例子来说明一下,使用流的好处。如下所示,我们将一个大文件读取到另一个文件中:

const fs = require('fs')

fs.readFile('./big.file', (err, data) => {if (err) throw errfs.writeFile('./out', data, () => {})
}) 

通过活动监视器,我们发现该进程内存占用为 300 MB 左右:

如果,我们换成流,情况就不一样了:

const fs = require('fs')

const readStream = fs.createReadStream('./big.file')
const writeStream = fs.createWriteStream('./out')
readStream.pipe(writeStream) 

看来 Stream 在处理大数据的时候是非常好的工具,接下来就让我们通过打比方的方式来进行理解吧。

通过比喻来理解 Stream

Readable Stream

首先,对于 Readable Stream,我们可以把他比喻成一个水龙头:

水龙头的水来自于哪,需要具体的 Readable Stream 来实现。比如 fs.createReadStream 创建的 Readable Stream 其水源自于文件,process.stdin 水源自于标准输入。

两个状态 flowing 和 paused

水龙头有两个状态 flowingpaused,即龙头打开或关闭。初始化一个 Readable Stream 时,默认是关闭的:

const readStream = fs.createReadStream('./file')
console.log(readStream._readableState.flowing, readStream._readableState.paused) // false true 

当我们监听 data 事件时,会自动打开开关:

const readStream = fs.createReadStream('./file')
readStream.on('data', (chunk) => {console.log(chunk)
})
console.log(readStream._readableState.flowing, readStream._readableState.paused) // true false 

且会通知水源往龙头中灌水,这样,水就流到了 data 事件的回调函数中:

我们也可以通过 resume 方法来手动开启水龙头,不过要小心,有可能导致水丢失:

const readStream = fs.createReadStream('./file')
readStream.resume()
setTimeout(() => {readStream.on('data', console.log) // 打印为空
}, 1000) 

这就好比先把水龙头打开了,然后再放桶子,肯定会漏掉一些水。

当然,我们也可以调用 pause 关闭水龙头,比如下面这个例子在接收到第一批水后就关闭了水龙头:

const readStream = fs.createReadStream('./big.file')

readStream.once('data', (chunk) => {readStream.pause()
}) 

buffer

上面代码调用 pause 后水源的水不会停止,会流到水龙头的一个 buffer 中,直到达到 highWaterMark (最高水位线)则停止:

我们可以通过代码验证一下:

const readStream = fs.createReadStream('./big.file')

readStream.once('data', (chunk) => {readStream.pause()setTimeout(() => {console.log(readStream._readableState.length, // 水龙头 buffer 的大小readStream._readableState.highWaterMark // 最高水位线) // 65536 65536}, 1000)
}) 

而且,我们可以重新再次打开水龙头,此时会先消耗掉 buffer 中的水,然后再从源头读取,比如下面这个例子(文末 ChatGPT 给的例子也可以):


                
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值