2022-08-29 23:02:28
注释掉 req.on('data') 请求一直挂着的原因是因为可读流 req 没有被切换到流动模式。
在 Node.js 中,可读流对象提供了两种模式:流动模式(flowing)和暂停模式(paused)。理解这两种模式对于正确处理流数据至关重要。
流动模式(Flowing)在流动模式下,数据会自动从底层系统获取,并通过 EventEmitter 提供的事件接口,尽可能快地提供给应用程序。当可读流处于流动模式时,一旦有数据可读,就会立即触发 'data' 事件,并将数据块传递给注册的事件处理函数。
要使可读流切换到流动模式,可以通过以下几种方式:
注册 'data' 事件:为可读流对象注册一个 'data' 事件,传入事件处理函数。这是最常见的方式,也是问题中提到的关键点。当注册了 'data' 事件后,可读流会自动切换到流动模式。
使用 pipe() 方法:调用 pipe() 方法将数据发送到可写流。pipe() 方法的内部实现也是通过注册 'data' 事件来实现的,它会一边读取数据一边写入数据至可写流。
调用 resume() 方法:如果可读流处于暂停模式,可以调用 resume() 方法来恢复触发 'data' 事件,从而切换到流动模式。
暂停模式是流一开始所处的模式。在该模式下,不会自动触发 'data' 事件来提供数据。相反,会触发 'readable' 事件,表示流中有可读取的数据。在暂停模式下,需要不断调用 read() 方法来拉取数据,直到返回 null,表示缓冲区中的数据已被耗尽。
问题分析在问题中的代码示例中,如果注释掉 req.on('data') 事件监听,可读流 req 将保持在暂停模式。由于没有注册 'data' 事件,也没有调用 resume() 方法或使用 pipe() 方法,可读流不会自动切换到流动模式。因此,即使有数据到达,也不会触发任何事件来处理这些数据。
由于 'end' 事件是在所有数据都被处理完毕后才会触发的,而在暂停模式下,数据没有被处理,因此 'end' 事件也不会被触发。这就导致了请求一直被挂起,因为服务器在等待 'end' 事件来结束响应。
解决方案要使请求不被挂起,可以通过以下方式之一来切换可读流到流动模式:
恢复 req.on('data') 事件监听:这是最直接的方式,通过注册 'data' 事件处理函数来切换流动模式。
调用 req.resume():如果不需要处理数据,只是希望流能够继续流动并触发 'end' 事件,可以调用 req.resume() 方法。这将使流切换到流动模式,并耗尽流中的数据(尽管在这个例子中数据没有被实际使用)。
使用异步迭代:对于支持异步迭代的 Node.js 版本,可以使用 for...await of 语法来遍历可读流。这种方式在代码上更简洁,也更容易理解。
综上所述,注释掉 req.on('data') 请求一直挂着的原因是因为可读流没有被切换到流动模式。通过理解流动模式和暂停模式的区别,以及如何通过不同方式切换这两种模式,可以正确地处理 Node.js 中的流数据。