为何stream.read()或stream.once('readable')无错误终止Node.js进程?
Node.js 空文件读取中
readable.read()与readable.once('readable')的行为解析 问题现象
读取空文件test.txt时,代码预期会抛出错误或无限挂起,但实际仅输出0、1后,进程以状态码0正常终止。
测试代码
const { createReadStream } = require('fs'); process.on('unhandledRejection', error => { console.log(error) }); process.on('error', e => { console.log('error', e) }); process.on('exit', e => { console.log('exit', e) }); (async () => { // test.txt 是一个空文件 const stream = createReadStream('test.txt', { encoding: 'utf-8' }) const waitForReadable = () => new Promise(r => stream.once('readable', r)) for (let i = 0; i < 1000; i += 1) { console.log(i) stream.read() await waitForReadable() } })()
实际输出
0 1 exit 0
原因解析
这是Node.js Readable流特性与事件循环机制共同作用的结果,具体流程如下:
第一次循环(i=0)
- 打印
0后调用stream.read(),此时流仍在异步读取文件,返回null并继续执行读取流程。 - 执行
await waitForReadable()为流添加readable事件监听,随后流读取到空文件末尾,触发readable事件(流结束时会触发一次readable),Promise resolve,await完成后进入第二次循环。
- 打印
第二次循环(i=1)
- 打印
1后调用stream.read(),此时流已读取到文件末尾,返回null,同时流触发end事件并关闭。 - 执行
await waitForReadable()再次添加readable监听,但流已结束,不会再触发readable事件,此时Promise处于pending状态。
- 打印
进程退出
- Node.js的事件循环会在没有待处理任务(如定时器、活跃流、网络请求等)时直接终止进程。由于流已关闭,没有其他事件源维持事件循环,即使存在pending的Promise,进程也会直接退出,导致循环无法继续执行后续迭代。
补充说明
- Readable流在到达文件末尾时,会触发一次
readable事件,此时调用read()会返回null表示流结束。 - 流结束后,
readable事件不会再次触发,因此后续添加的readable监听永远不会执行。 - Node.js不会为pending的Promise单独维持事件循环,必须存在其他活跃的事件源(如未关闭的流、定时器等),进程才会持续运行。
内容的提问来源于stack exchange,提问作者Konrad
相关产品推荐
相关产品推荐

