流实现者的 API
node:stream
模块 API 旨在使使用 JavaScript 的原型继承模型轻松实现流成为可能。
首先,流开发者将声明新的 JavaScript 类,该类扩展四个基本流类(stream.Writable
、stream.Readable
、stream.Duplex
或 stream.Transform
)之一,确保它们调用适当的父类构造函数:
const { Writable } = require('node:stream');
class MyWritable extends Writable {
constructor({ highWaterMark, ...options }) {
super({ highWaterMark });
// ...
}
}
当扩展流时,在将这些选项转发给基本构造函数之前,请记住用户可以和应该提供哪些选项。
例如,如果实现对 autoDestroy
和 emitClose
选项做出假设,则不允许用户覆盖这些。
显式转发哪些选项,而不是隐式转发所有选项。
然后,新的流类必须实现一个或多个特定方法,具体取决于正在创建的流的类型,如下图所示:
Use-case | Class | Method(s) to implement |
---|---|---|
只读 | Readable | _read() |
只写 | Writable | _write() , _writev() , _final() |
可读可写 | Duplex | _read() , _write() , _writev() , _final() |
对写入的数据进行操作,然后读取结果 | Transform | _transform() , _flush() , _final() |
流的实现代码永远不应该调用供消费者使用的流的“公共”方法(如流消费者的 API 章节所述)。 这样做可能会对使用流的应用程序代码产生不利的副作用。
避免覆盖公共方法,例如 write()
、end()
、cork()
、uncork()
、read()
和 destroy()
,或触发内部事件,例如 'error'
、'data'
、'end'
、'finish'
和 'close'
到 .emit()
。
这样做可能会破坏当前和未来的流的不变量,从而导致行为和/或与其他流、流实用程序和用户期望的兼容性问题。
The node:stream
module API has been designed to make it possible to easily
implement streams using JavaScript's prototypal inheritance model.
First, a stream developer would declare a new JavaScript class that extends one
of the four basic stream classes (stream.Writable
, stream.Readable
,
stream.Duplex
, or stream.Transform
), making sure they call the appropriate
parent class constructor:
const { Writable } = require('node:stream');
class MyWritable extends Writable {
constructor({ highWaterMark, ...options }) {
super({ highWaterMark });
// ...
}
}
When extending streams, keep in mind what options the user
can and should provide before forwarding these to the base constructor. For
example, if the implementation makes assumptions in regard to the
autoDestroy
and emitClose
options, do not allow the
user to override these. Be explicit about what
options are forwarded instead of implicitly forwarding all options.
The new stream class must then implement one or more specific methods, depending on the type of stream being created, as detailed in the chart below:
Use-case | Class | Method(s) to implement |
---|---|---|
Reading only | Readable | _read() |
Writing only | Writable | _write() , _writev() , _final() |
Reading and writing | Duplex | _read() , _write() , _writev() , _final() |
Operate on written data, then read the result | Transform | _transform() , _flush() , _final() |
The implementation code for a stream should never call the "public" methods of a stream that are intended for use by consumers (as described in the API for stream consumers section). Doing so may lead to adverse side effects in application code consuming the stream.
Avoid overriding public methods such as write()
, end()
, cork()
,
uncork()
, read()
and destroy()
, or emitting internal events such
as 'error'
, 'data'
, 'end'
, 'finish'
and 'close'
through .emit()
.
Doing so can break current and future stream invariants leading to behavior
and/or compatibility issues with other streams, stream utilities, and user
expectations.