writable.write(chunk[, encoding][, callback])


  • chunk <string> | <Buffer> | <TypedArray> | <DataView> | <any> 要写入的可选数据。对于非对象模式的流,chunk 必须是 <string><Buffer><TypedArray><DataView>。对于对象模式的流,chunk 可以是除 null 之外的任何 JavaScript 值。
  • encoding <string> | <null> 如果 chunk 是字符串,则指定其编码。默认值: 'utf8'
  • callback <Function> 当这一块数据被刷新时的回调。
  • 返回值:<boolean> 如果流希望调用代码在继续写入额外数据之前等待 'drain' 事件被触发,则返回 false;否则返回 true

writable.write() 方法将一些数据写入流,并在数据完全处理后调用提供的 callback。如果发生错误,callback 将以错误作为其第一个参数被调用。callback 是异步调用的,并且在 'error' 事件触发之前调用。

【The writable.write() method writes some data to the stream, and calls the supplied callback once the data has been fully handled. If an error occurs, the callback will be called with the error as its first argument. The callback is called asynchronously and before 'error' is emitted.】

如果在接收 chunk 后内部缓冲区小于创建流时配置的 highWaterMark,返回值为 true。如果返回 false,应停止向流写入数据,直到发出 'drain' 事件。

【The return value is true if the internal buffer is less than the highWaterMark configured when the stream was created after admitting chunk. If false is returned, further attempts to write data to the stream should stop until the 'drain' event is emitted.】

当流没有排空时,对 write() 的调用会将 chunk 缓存起来,并返回 false。一旦所有当前缓冲的块被排空(被操作系统接受交付),将触发 'drain' 事件。一旦 write() 返回 false,不要写入更多的块,直到 'drain' 事件被触发。虽然可以在流未排空时调用 write(),Node.js 会缓存所有写入的块,直到达到最大内存使用量,此时将无条件中止。即使在中止之前,高内存使用也会导致垃圾回收器性能下降和 RSS 占用高(即使内存不再需要,也通常不会释放回系统)。由于如果远程端没有读取数据,TCP 套接字可能永远不会排空,因此向未排空的套接字写入数据可能导致远程可利用的安全漏洞。

【While a stream is not draining, calls to write() will buffer chunk, and return false. Once all currently buffered chunks are drained (accepted for delivery by the operating system), the 'drain' event will be emitted. Once write() returns false, do not write more chunks until the 'drain' event is emitted. While calling write() on a stream that is not draining is allowed, Node.js will buffer all written chunks until maximum memory usage occurs, at which point it will abort unconditionally. Even before it aborts, high memory usage will cause poor garbage collector performance and high RSS (which is not typically released back to the system, even after the memory is no longer required). Since TCP sockets may never drain if the remote peer does not read the data, writing a socket that is not draining may lead to a remotely exploitable vulnerability.】

在流未排空时写入数据对 Transform 来说特别有问题,因为 Transform 流默认是暂停的,直到它们被管道连接或添加了 'data''readable' 事件处理程序。

【Writing data while the stream is not draining is particularly problematic for a Transform, because the Transform streams are paused by default until they are piped or a 'data' or 'readable' event handler is added.】

如果要写入的数据可以按需生成或获取,建议将逻辑封装到 Readable 中并使用 stream.pipe()。然而,如果更倾向于调用 write(),可以使用 'drain' 事件来遵守背压并避免内存问题:

【If the data to be written can be generated or fetched on demand, it is recommended to encapsulate the logic into a Readable and use stream.pipe(). However, if calling write() is preferred, it is possible to respect backpressure and avoid memory issues using the 'drain' event:】

function write(data, cb) {
  if (!stream.write(data)) {
    stream.once('drain', cb);
  } else {
    process.nextTick(cb);
  }
}

// Wait for cb to be called before doing any other write.
write('hello', () => {
  console.log('Write completed, do more writes now.');
}); 

处于对象模式的 Writable 流将始终忽略 encoding 参数。

【A Writable stream in object mode will always ignore the encoding argument.】