努力理解可读流上的 highWaterMark

Tim*_*Tim 6 node.js busboy node-streams

我发现 Busboy 和节点流 highWaterMark 属性存在一些我不理解的行为。我预计块的大小最大为 highWaterMark 值,但块大小看起来不受 highWaterMark 设置的影响。

我已经fileHwm: 5在 Busboy 中设置了选项,并且我的快速路线设置如下

app.post('/upload', function(req, res, next) {
  req.pipe(req.busboy); // Pipe it through busboy
  req.busboy.on('file', (fieldname, file, filename) => {
      console.log(`Upload of '${filename}' started`);
      console.log(file);
      file.on('readable', () => {
        let chunk;
        while (null !== (chunk = file.read())) {
          console.log(`Received ${chunk.length} bytes of data.`);
        }
      });

  });
});
Run Code Online (Sandbox Code Playgroud)

当我登录时file,看起来不错,并且我看到该highWaterMark属性已设置得很好

FileStream {
  _readableState:
   ReadableState {
     objectMode: false,
     highWaterMark: 5,
...
Run Code Online (Sandbox Code Playgroud)

但我得到的块的大小并不5像我预期的那样 - 相反我看到

Received 65395 bytes of data.
Received 65536 bytes of data.
Received 65536 bytes of data.
Received 65536 bytes of data.
Run Code Online (Sandbox Code Playgroud)

那么什么给出呢?我原本预计read一次只返回 5 个字节。并不是说 65kb 大小不好,而是很好。我只是希望我了解发生了什么,以及是否可以限制缓冲区大小。

Fel*_*nda 2

可读流和可写流都维护内部队列,它们用于类似的目的。在可读流的情况下,内部队列包含已由底层源排队但尚未被使用者读取的块。对于可写流,内部队列包含已由生产者写入流但尚未由底层接收器处理和确认的块。

\n

排队策略是一个对象,它确定流应如何根据其内部队列的状态发出反压信号。排队策略为每个块分配一个大小,并将队列中所有块的总大小与指定数字(称为高水位线)进行比较。所得差异(高水位线减去总大小)用于确定填充stream\xe2\x80\x99s 队列所需的大小。

\n

对于可读流,底层源可以使用该所需大小作为反压信号,减慢块生成,以便尝试将所需大小保持在零以上或为零。对于可写流,生产者可以采取类似的行为,避免可能导致所需大小变为负数的写入。

\n

具体来说,Web 开发人员\xe2\x80\x93 创建的流的排队策略由任何具有 highWaterMark 属性的 JavaScript 对象给出。对于字节流,highWaterMark 始终以字节为单位。对于其他流,默认单位是块,但size()策略对象中可以包含一个函数,该函数返回给定块的大小。这允许以任意浮点单位指定 highWaterMark。

\n

排队策略的一个简单示例是为每个块分配大小 1,并且高水位标记为 3。这意味着在流被认为正在施加反压之前,最多可以将三个块放入可读流中,或者将三个块写入可写流。\n在 JavaScript 中,可以将这样的策略手动编写为 , 或{ highWaterMark: 3, size() { return 1; }}使用内置CountQueuingStrategy类,如new CountQueuingStrategy({ highWaterMark: 3 }).

\n

参考:https: //streams.spec.whatwg.org/#high-water-mark

\n