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

为何绑定readable事件后process.stdin.read被调用两次?如何正确Mock?

为什么process.stdin.read会被调用两次?

这事儿我太熟了,本质是Node.js的Readable流内部机制在起作用,咱们一步步拆解:

两次调用的来源

你看到的两次read调用,分别来自两个地方:

  1. 第一次调用(无参数):就是你在readable事件回调里显式写的process.stdin.read(),完全是你主动触发的。
  2. 第二次调用(参数为0):这是Node.js Readable流的内部自动调用。当readable事件的用户回调执行完成后,流会自动调用read(0)——这个调用的目的是触发流的状态检查:确认是否还有剩余数据需要推送,或者是否要切换到flowing模式,再或者判断是否应该结束流。不管是自然触发的readable事件,还是你手动emit('readable'),这个内部调用都会发生。

你的Mock代码为什么出问题?

看你的callerFn逻辑,它把参数当成bool判断,当参数是0时返回null,否则就消耗生成器的yield值。但问题在于:

  • 第一次调用是无参数(args: []),此时bool是undefined,不等于0,所以会消耗生成器的第一个值;
  • 第二次内部调用传了0,虽然返回null,但如果后续还有业务逻辑需要读取数据,生成器已经没有值可以yield了——这就导致你的Mock无法正常提供后续数据。

修复方案

调整Mock逻辑,忽略size为0的内部调用,不消耗生成器的内容,同时规范处理read方法的参数(size表示读取的字节数,不是布尔值):

const mockStdinRead = (message) => {
  const gen = function * () {
    yield message
  }
  const it = gen()
  const callerFn = (size) => {
    // 对于内部的read(0)调用,直接返回null,不消耗生成器
    if (size === 0) return null;
    // 读取生成器的值,没有值时返回null(符合流的结束规范)
    const result = it.next().value;
    return result ?? null;
  }
  return callerFn
}

用这个Mock测试你的代码,就能看到:

  • 你主动调用的read()会拿到预设的message;
  • 内部的read(0)调用只会返回null,不会消耗生成器的内容,完全不影响你的业务逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:44:19