You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中stream.Readable的'readable'事件触发时机及代码运行疑问

为什么Node.js Readable流没手动调用_read()也能触发readable事件?

先贴一下你的代码方便对照:

const stream = require('stream')
const readable = new stream.Readable({ encoding: 'utf8', highWaterMark: 16000, objectMode: false })
const news = [ 'News #1', 'News #2', 'News #3' ]
readable._read = () => {
  if(news.length) {
    return readable.push(news.shift() + '\n')
  }
  return readable.push(null)
}
readable.on('readable', () => {
  let data = readable.read()
  if(data) {
    process.stdout.write(data)
  }
})
readable.on('end', () => {
  console.log('No more feed')
})

嘿,这个问题问得特别好——刚接触Node.js流的时候,确实会被这种“自动干活”的逻辑搞懵,我当初学的时候也卡过这儿😉

核心原因其实是Node.js的Readable流会自动管理数据的填充流程,不需要你手动去调用_read()或者推送数据,具体来说是这几个关键点:

1. 监听readable事件等于给流发了“消费信号”

当你给流绑定readable事件回调的时候,就相当于告诉流:“我准备好接收数据啦,快把数据弄过来”。此时Node.js的流内部机制会自动触发你重写的_read()方法,开始往缓冲区里填充数据。

2. _read()是流的“数据供应入口”

你重写的_read()方法是流的数据源逻辑——流每次需要数据的时候(比如缓冲区空了、刚有消费者监听),就会自动调用这个方法,然后你通过push()把数据放到流的内部缓冲区里。

当你push(null)的时候,就是在告诉流:“没数据了,我要结束了”,这时候流后续就会触发end事件。

3. 整个流程的自动运转逻辑

咱们把你的代码走一遍流程就清楚了:

  • 初始化readable流,并且定义了_read()的数据源逻辑;
  • 你绑定了readable事件,流检测到有消费者,立刻调用_read();
  • _read()把News #1推到缓冲区,此时缓冲区有数据了,就触发readable事件;
  • 你在回调里用read()把数据读出来输出到控制台;
  • 输出后缓冲区空了,流会再次调用_read(),继续推News #2,重复上面的步骤;
  • 直到news数组为空,push(null),流触发end事件,打印“No more feed”。

简单来说,Node.js的Readable流就是设计成“自动按需填充数据”的模式,开发者只需要负责提供数据源(写好_read())和处理数据(监听事件),剩下的驱动流程交给流内部去做就行啦。

内容的提问来源于stack exchange,提问作者user278077

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:36:39