目录
writable.end([chunk[, encoding]][, callback])
writable.setDefaultEncoding(encoding)
writable.writableHighWaterMark
writable.write(chunk[, encoding][, callback])
readable.pipe(destination[, options])
readable.readableHighWaterMark
readable.setEncoding(encoding)
readable.unpipe([destination])
readable.unshift(chunk[, encoding])
readable[Symbol.asyncIterator]()
stream.finished(stream[, options], callback)
stream.pipeline(...streams, callback)
stream.Readable.from(iterable, [options])
new stream.Writable([options])
writable._write(chunk, encoding, callback)
writable._writev(chunks, callback)
writable._destroy(err, callback)
new stream.Readable([options])
readable._destroy(err, callback)
readable.push(chunk[, encoding])
new stream.Transform([options])
transform._transform(chunk, encoding, callback)
调用 `readable.setEncoding()` 之后 `highWaterMark` 的差异
stream(流)
流(stream)是 Node.js 中处理流式数据的抽象接口。 stream
模块用于构建实现了流接口的对象。
Node.js 提供了多种流对象。 例如,HTTP 服务器的请求和 process.stdout
都是流的实例。
流可以是可读的、可写的、或者可读可写的。 所有的流都是 EventEmitter
的实例。
访问 stream
模块:
const stream = require('stream');
流的类型
Node.js 中有四种基本的流类型:
Writable
- 可写入数据的流(例如fs.createWriteStream()
)。Readable
- 可读取数据的流(例如fs.createReadStream()
)。Duplex
- 可读又可写的流(例如net.Socket
)。Transform
- 在读写过程中可以修改或转换数据的Duplex
流(例如zlib.createDeflate()
)。
此外,该模块还包括实用函数 stream.pipeline()
、stream.finished()
和 stream.Readable.from()
。
对象模式
Node.js 创建的流都是运作在字符串和 Buffer
(或 Uint8Array
)上。 当然,流的实现也可以使用其它类型的 JavaScript 值(除了 null
)。 这些流会以“对象模式”进行操作。
当创建流时,可以使用 objectMode
选项把流实例切换到对象模式。 将已存在的流切换到对象模式是不安全的。
缓冲
可写流和可读流都会在内部的缓冲器中存储数据,可以分别使用的 writable.writableBuffer
或 readable.readableBuffer
来获取。
可缓冲的数据大小取决于传入流构造函数的 highWaterMark
选项。 对于普通的流, highWaterMark
指定了字节的总数。 对于对象模式的流, highWaterMark
指定了对象的总数。
当调用 stream.push(chunk)
时,数据会被缓冲在可读流中。 如果流的消费者没有调用 stream.read()
,则数据会保留在内部队列中直到被消费。
一旦内部的可读缓冲的总大小达到 highWaterMark
指定的阈值时,流会暂时停止从底层资源读取数据,直到当前缓冲的数据被消费 (也就是说,流会停止调用内部的用于填充可读缓冲的 readable._read()
)。
当调用 writable.write(chunk)
时,数据会被缓冲在可写流中。 当内部的可写缓冲的总大小小于 highWaterMark
设置的阈值时,调用 writable.write()
会返回 true
。 一旦内部缓冲的大小达到或超过 highWaterMark
时,则会返回 false
。
stream
API 的主要目标,特别是 stream.pipe()
,是为了限制数据的缓冲到可接受的程度,也就是读写速度不一致的源头与目的地不会压垮内存。
因为 Duplex
和 Transform
都是可读又可写的,所以它们各自维护着两个相互独立的内部缓冲器用于读取和写入, 这使得它们在维护数据流时,读取和写入两边可以各自独立地运作。 例如,net.Socket
实例是 Duplex
流,它的可读端可以消费从 socket 接收的数据,而可写端则可以将数据写入到 socket。 因为数据写入到 socket 的速度可能比接收数据的速度快或者慢,所以读写两端应该独立地进行操作(或缓冲)。
用于消费流的 API
const http = require('http');
const server = http.createServer((req, res) => {
// req 是一个 http.IncomingMessage 实例,它是可读流。
// res 是一个 http.ServerResponse 实例,它是可写流。
let body = '';
// 接收数据为 utf8 字符串,
// 如果没有设置字符编码,则会接收到 Buffer 对象。
req.setEncoding('utf8');
// 如果添加了监听器,则可读流会触发 'data' 事件。
req.on('data', (chunk) => {
body += chunk;
});
// 'end' 事件表明整个请求体已被接收。
req.on('end', () => {
try {
const data = JSON.parse(body);
// 响应信息给用户。
res.write(typeof data);
res.end();
} catch (er) {
// json 解析失败。
res.statusCode = 400;
return res.end(`错误: ${er.message}`);
}
});
});
server.listen(1337);
// $ curl localhost:1337 -d "{}"
// object
// $ curl localhost:1337 -d "\"foo\""
// string
// $ curl localhost:1337 -d "not json"
// 错误: Unexpected token o in JSON at position 1
几乎所有的 Node.js 应用都在某种程度上使用了流。 下面是一个例子,使用流实现了一个 HTTP 服务器:
可写流(比如例子中的 res
)会暴露了一些方法,比如 write()
和 end()
用于写入数据到流。
当数据可以从流读取时,可读流会使用 EventEmitter
API 来通知应用程序。 从流读取数据的方式有很多种。
可写流和可读流都通过多种方式使用 EventEmitter
API 来通讯流的当前状态。
Duplex
流和 Transform
流都是可写又可读的。
对于只需写入数据到流或从流消费数据的应用程序,并不需要直接实现流的接口,通常也不需要调用 require('stream')
。
对于需要实现新类型的流的开发者,可以参阅用于实现流的API章节。
可写流
可写流是对数据要被写入的目的地的一种抽象。
可写流的例子包括:
上面的一些例子事实上是实现了可写流接口的 Duplex
流。
所有可写流都实现了 stream.Writable
类定义的接口。
尽管可写流的具体实例可能略有差别,但所有的可写流都遵循同一基本的使用模式,如以下例子所示:
stream.Writable 类
const myStream = getWritableStreamSomehow();
myStream.write('一些数据');
myStream.write('更多数据');
myStream.end('完成写入数据');
'close' 事件
当流或其底层资源(比如文件描述符)被关闭时触发。 表明不会再触发其他事件,也不会再发生操作。
如果使用 emitClose
选项创建可写流,则它将会始终发出 'close'
事件。
'drain' 事件
如果调用 stream.write(chunk)
返回 false
,则当可以继续写入数据到流时会触发 'drain'
事件。
// 向可写流中写入数据一百万次。
// 留意背压(back-pressure)。
function writeOneMillionTimes(writer, data, encoding, callback) {
let i = 1000000;
write();
function write() {
let ok = true;
do {
i--;
if (i === 0) {
// 最后一次写入。
writer.write(data, encoding, callback);
} else {
// 检查是否可以继续写入。
// 不要传入回调,因为写入还没有结束。
ok = writer.write(data, encoding);
}
} while (i > 0 && ok);
if (i > 0) {
// 被提前中止。
// 当触发 'drain' 事件时继续写入。
writer.once('drain', write);
}
}
}
'error' 事件
<Error>
如果在写入或管道数据时发生错误,则会触发 'error' 事件。 当调用时,监听器回调会传入一个 Error 参数。
除非在创建流时将 autoDestroy 选项设置为 true,否则在触发 'error' 事件时不会关闭流。
'finish' 事件
调用 stream.end()
且缓冲数据都已传给底层系统之后触发。
'pipe' 事件
src
<stream.Readable> 通过管道流入到可写流的来源流。
当在可读流上调用 stream.pipe()
方法时会发出 'pipe'
事件,并将此可写流添加到其目标集。
'unpipe' 事件
src
<stream.Readable> 要移除可写流管道的来源流。
在可读流上调用 stream.unpipe()
方法时会发出 'unpipe'
事件,从其目标集中移除此可写流。
当可读流通过管道流向可写流发生错误时,也会触发此事件。
writable.cork()
writable.cork()
方法强制把所有写入的数据都缓冲到内存中。 当调用 stream.uncork()
或 stream.end()
时,缓冲的数据才会被输出。
当写入大量小块数据到流时,内部缓冲可能失效,从而导致性能下降, writable.cork()
主要用于避免这种情况。 对于这种情况,实现了 writable._writev()
的流可以用更优的方式对写入的数据进行缓冲。
writable.destroy([error])
销毁流。 可选地触发 'error'
,并且触发 'close'
事件(除非将 emitClose
设置为 false
)。 调用该方法后,可写流就结束了,之后再调用 write()
或 end()
都会导致 ERR_STREAM_DESTROYED
错误。 这是销毁流的最直接的方式。 前面对 write()
的调用可能没有耗尽,并且可能触发 ERR_STREAM_DESTROYED
错误。 如果数据在关闭之前应该刷新,则使用 end()
而不是销毁,或者在销毁流之前等待 'drain'
事件。 实现者不应该重写此方法,而应该实现 writable._destroy()
。
writable.destroyed
在调用了 writable.destroy()
之后为 true
。
writable.end([chunk[, encoding]][, callback])
chunk
<string> | <Buffer> | <Uint8Array> | <any> 要写入的数据。 对于非对象模式的流,chunk
必须是字符串、Buffer
、或Uint8Array
。 对于对象模式的流,chunk
可以是任何 JavaScript 值,除了null
。encoding
<string> 如果chunk
是字符串,则指定字符编码。callback
<Function> 当流结束时的回调函数。- 返回: <this>
调用 writable.end()
表明已没有数据要被写入可写流。 可选的 chunk
和 encoding
参数可以在关闭流之前再写入一块数据。 如果传入了 callback
函数,则会做为监听器添加到 'finish'
事件。
调用 stream.end()
之后再调用 stream.write()
会导致错误。
writable.setDefaultEncoding(encoding)
writable.setDefaultEncoding()
方法为可写流设置默认的 encoding
。
writable.uncork()
writable.uncork()
方法将调用 stream.cork()
后缓冲的所有数据输出到目标。
当使用 writable.cork()
和 writable.uncork()
来管理流的写入缓冲时,建议使用 process.nextTick()
来延迟调用 writable.uncork()
。 通过这种方式,可以对单个 Node.js 事件循环中调用的所有 writable.write()
进行批处理。
如果一个流上多次调用 writable.cork()
,则必须调用同样次数的 writable.uncork()
才能输出缓冲的数据。
writable.writable
如果调用 writable.write()
是安全的,则为 true
。
writable.writableEnded
在调用了 writable.end()
之后为 true
。 此属性不表明数据是否已刷新,对此请使用 writable.writableFinished
。
writable.writableFinished
在触发 'finish'
事件之前立即设置为 true
。
writable.writableHighWaterMark
返回构造可写流时传入的 highWaterMark
的值。
writable.writableLength
此属性包含准备写入的队列中的字节数(或对象)。 该值提供有关 highWaterMark
状态的内省数据。
writable.writableObjectMode
获取用于给定 Writable
流的 objectMode
属性。
writable.write(chunk[, encoding][, callback])
chunk
<string> | <Buffer> | <Uint8Array> | <any> 要写入的数据。 对于非对象模式的流,chunk
必须是字符串、Buffer
或Uint8Array
。 对于对象模式的流,chunk
可以是任何 JavaScript 值,除了null
。encoding
<string> 如果chunk
是字符串,则指定字符编码。callback
<Function> 当数据块被输出到目标后的回调函数。- 返回: <boolean> 如果流需要等待
'drain'
事件触发才能继续写入更多数据,则返回false
,否则返回true
。
writable.write()
写入数据到流,并在数据被完全处理之后调用 callback
。 如果发生错误,则 callback
可能被调用也可能不被调用。 为了可靠地检测错误,可以为 'error'
事件添加监听器。
在接收了 chunk
后,如果内部的缓冲小于创建流时配置的 highWaterMark
,则返回 true
。 如果返回 false
,则应该停止向流写入数据,直到 'drain'
事件被触发。
当流还未被排空时,调用 write()
会缓冲 chunk
,并返回 false
。 一旦所有当前缓冲的数据块都被排空了(被操作系统接收并传输),则触发 'drain'
事件。 建议一旦 write()
返回 false,则不再写入任何数据块,直到 'drain'
事件被触发。 当流还未被排空时,也是可以调用 write()
,Node.js 会缓冲所有被写入的数据块,直到达到最大内存占用,这时它会无条件中止。 甚至在它中止之前, 高内存占用将会导致垃圾回收器的性能变差和 RSS 变高(即使内存不再需要,通常也不会被释放回系统)。 如果远程的另一端没有读取数据,TCP 的 socket 可能永远也不会排空,所以写入到一个不会排空的 socket 可能会导致远程可利用的漏洞。
对于 Transform
, 写入数据到一个不会排空的流尤其成问题,因为 Transform
流默认会被暂停,直到它们被 pipe 或者添加了 'data'
或 'readable'
事件句柄。
如果要被写入的数据可以根据需要生成或者取得,建议将逻辑封装为一个可读流并且使用 stream.pipe()
。 如果要优先调用 write()
,则可以使用 'drain'
事件来防止背压与避免内存问题:
对象模式下的可写流将会始终忽略 encoding
参数。
可读流
可读流是对提供数据的来源的一种抽象。
可读流的例子包括:
所有可读流都实现了 stream.Readable
类定义的接口。
两种读取模式
可读流运作于两种模式之一:流动模式(flowing)或暂停模式(paused)。 这些模式与对象模式分开。 无论是否处于流动模式或暂停模式,可读流都可以处于对象模式。
- 在流动模式中,数据自动从底层系统读取,并通过
EventEmitter
接口的事件尽可能快地被提供给应用程序。 - 在暂停模式中,必须显式调用
stream.read()
读取数据块。
所有可读流都开始于暂停模式,可以通过以下方式切换到流动模式:
- 添加
'data'
事件句柄。 - 调用
stream.resume()
方法。 - 调用
stream.pipe()
方法将数据发送到可写流。
可读流可以通过以下方式切换回暂停模式:
- 如果没有管道目标,则调用
stream.pause()
。 - 如果有管道目标,则移除所有管道目标。调用
stream.unpipe()
可以移除多个管道目标。
只有提供了消费或忽略数据的机制后,可读流才会产生数据。 如果消费的机制被禁用或移除,则可读流会停止产生数据。
为了向后兼容,移除 'data'
事件句柄不会自动地暂停流。 如果有管道目标,一旦目标变为 drain
状态并请求接收数据时,则调用 stream.pause()
也不能保证流会保持暂停模式。
如果可读流切换到流动模式,且没有可用的消费者来处理数据,则数据将会丢失。 例如,当调用 readable.resume()
时,没有监听 'data'
事件或 'data'
事件句柄已移除。
添加 'readable'
事件句柄会使流自动停止流动,并通过 readable.read()
消费数据。 如果 'readable'
事件句柄被移除,且存在 'data'
事件句柄,则流会再次开始流动。
三种状态
可读流的两种模式是对发生在可读流中更加复杂的内部状态管理的一种简化的抽象。
在任意时刻,可读流会处于以下三种状态之一:
readable.readableFlowing === null
readable.readableFlowing === false
readable.readableFlowing === true
当 readable.readableFlowing
为 null
时,没有提供消费流数据的机制,所以流不会产生数据。 在这个状态下,监听 'data'
事件、调用 readable.pipe()
、或调用 readable.resume()
都会使 readable.readableFlowing
切换到 true
,可读流开始主动地产生数据并触发事件。
调用 readable.pause()
、 readable.unpipe()
、或接收到背压,则 readable.readableFlowing
会被设为 false
,暂时停止事件流动但不会停止数据的生成。 在这个状态下,为 'data'
事件绑定监听器不会使 readable.readableFlowing
切换到 true
。
当 readable.readableFlowing
为 false
时,数据可能会堆积在流的内部缓冲中。
选择一种接口风格
可读流的 API 贯穿了多个 Node.js 版本,且提供了多种方法来消费流数据。 开发者通常应该选择其中一种方法来消费数据,不要在单个流使用多种方法来消费数据。 混合使用 on('data')
、 on('readable')
、 pipe()
或异步迭代器,会导致不明确的行为。
对于大多数用户,建议使用 readable.pipe()
,因为它是消费流数据最简单的方式。 如果开发者需要精细地控制数据的传递与产生,可以使用 EventEmitter
、 readable.on('readable')
/readable.read()
或 readable.pause()
/readable.resume()
。
stream.Readable 类
'close' 事件
当流或其底层资源(比如文件描述符)被关闭时触发 'close'
事件。 该事件表明不会再触发其他事件,也不会再发生操作。
如果使用 emitClose
选项创建可读流,则它将会始终发出 'close'
事件。
'data' 事件
chunk
<Buffer> | <string> | <any> 数据块。 对于非对象模式的流,chunk
可以是字符串或Buffer
。 对于对象模式的流,chunk
可以是任何 JavaScript 值,除了null
。
当流将数据块传送给消费者后触发。 当调用 readable.pipe()
, readable.resume()
或绑定监听器到 'data'
事件时,流会转换到流动模式。 当调用 readable.read()
且有数据块返回时,也会触发 'data'
事件。
将 'data'
事件监听器附加到尚未显式暂停的流将会使流切换为流动模式。 数据将会在可用时立即传递。
如果使用 readable.setEncoding()
为流指定了默认的字符编码,则监听器回调传入的数据为字符串,否则传入的数据为 Buffer
。
'end' 事件
当流中没有数据可供消费时触发。
'end'
事件只有在数据被完全消费掉后才会触发。 要想触发该事件,可以将流转换到流动模式,或反复调用 stream.read()
直到数据被消费完。
'error' 事件
'error'
事件可能随时由 Readable
实现触发。 通常,如果底层的流由于底层内部的故障而无法生成数据,或者流的实现尝试推送无效的数据块,则可能会发生这种情况。
监听器回调将会传入一个 Error
对象。
'pause' 事件
当调用 stream.pause()
并且 readsFlowing
不为 false
时,就会触发 'pause'
事件。
'readable' 事件
当有数据可从流中读取时,就会触发 'readable'
事件。 在某些情况下,为 'readable'
事件附加监听器将会导致将一些数据读入内部缓冲区。
当到达流数据的尽头时, 'readable'
事件也会触发,但是在 'end'
事件之前触发。
'readable'
事件表明流有新的动态:要么有新的数据,要么到达流的尽头。 对于前者,stream.read()
会返回可用的数据。 对于后者,stream.read()
会返回 null
。 例如,下面的例子中, foo.txt
是一个空文件:
通常情况下, readable.pipe()
和 'data'
事件的机制比 'readable'
事件更容易理解。 处理 'readable'
事件可能造成吞吐量升高。
如果同时使用 'readable'
事件和 'data'
事件,则 'readable'
事件会优先控制流,也就是说,当调用 stream.read()
时才会触发 'data'
事件。 readableFlowing
属性会变成 false
。 当移除 'readable'
事件时,如果存在 'data'
事件监听器,则流会开始流动,也就是说,无需调用 .resume()
也会触发 'data'
事件。
'resume' 事件
当调用 stream.resume()
并且 readsFlowing
不为 true
时,将会触发 'resume'
事件。
readable.destroy([error])
销毁流。 可选地触发 'error'
事件,并触发 'close'
事件(除非将 emitClose
设置为 false
)。 在此调用之后,可读流将会释放所有内部的资源,并且将会忽略对 push()
的后续调用。 实现者不应该重写此方法,而应该实现 readable._destroy()
。
readable.destroyed
在调用 readable.destroy()
之后为 true
。
readable.isPaused()
- 返回: <boolean>
readable.isPaused()
方法返回可读流当前的操作状态。 主要用于 readable.pipe()
底层的机制。 大多数情况下无需直接使用该方法。
readable.pause()
- 返回: <this>
readable.pause()
方法使流动模式的流停止触发 'data'
事件,并切换出流动模式。 任何可用的数据都会保留在内部缓存中。如果存在 'readable'
事件监听器,则 readable.pause()
方法不起作用。
readable.pipe(destination[, options])
destination
<stream.Writable> 数据写入的目标。-
options
<Object> 管道选项。end
<boolean> 当读取器结束时终止写入器。默认值:true
。
- 返回: <stream.Writable> 目标可写流,如果是
Duplex
流或Transform
流则可以形成管道链。
readable.pipe()
方法绑定可写流到可读流,将可读流自动切换到流动模式,并将可读流的所有数据推送到绑定的可写流。 数据流会被自动管理,所以即使可读流更快,目标可写流也不会超负荷。
例子,将可读流的所有数据通过管道推送到 file.txt
文件:
默认情况下,当来源可读流触发 'end'
事件时,目标可写流也会调用 stream.end()
结束写入。 若要禁用这种默认行为, end
选项应设为 false
,这样目标流就会保持打开:
readable.read([size])
从内部缓冲拉取并返回数据。 如果没有可读的数据,则返回 null
。 默认情况下, readable.read()
返回的数据是 Buffer
对象,除非使用 readable.setEncoding()
指定字符编码或流处于对象模式。
可选的 size
参数指定要读取的特定字节数。 如果无法读取 size
个字节,则除非流已结束,否则将会返回 null
,在这种情况下,将会返回内部 buffer 中剩余的所有数据。
如果没有指定 size
参数,则返回内部缓冲中的所有数据。
size
参数必须小于或等于 1 GB。
readable.read()
应该只对处于暂停模式的可读流调用。 在流动模式中, readable.read()
会自动调用直到内部缓冲的数据完全耗尽。
readable.readable
如果可以安全地调用 readable.read()
,则为 true
。
readable.readableEncoding
获取用于给定可读流的 encoding
属性。 可以使用 readable.setEncoding()
方法设置 encoding
属性。
readable.readableEnded
当 'end'
事件被触发时变为 true
。
readable.readableFlowing
This property reflects the current state of a Readable
stream as described in the Stream Three States section.
readable.readableHighWaterMark
返回构造可读流时传入的 highWaterMark
的值。
readable.readableLength
此属性包含准备读取的队列中的字节数(或对象数)。 该值提供有关 highWaterMark
状态的内省数据。
readable.readableObjectMode
获取用于给定可读流的 objectMode
属性。
readable.resume()
- 返回: <this>
readable.resume()
方法将被暂停的可读流恢复触发 'data'
事件,并将流切换到流动模式。
readable.resume()
方法可以用来充分消耗流中的数据,但无需实际处理任何数据:
readable.setEncoding(encoding)
readable.setEncoding()
方法为从可读流读取的数据设置字符编码。
默认情况下没有设置字符编码,流数据返回的是 Buffer
对象。 如果设置了字符编码,则流数据返回指定编码的字符串。 例如,调用 readable.setEncoding('utf-8')
会将数据解析为 UTF-8 数据,并返回字符串,调用 readable.setEncoding('hex')
则会将数据编码成十六进制字符串。
可读流将会正确地处理通过流传递的多字节字符,否则如果简单地从流中作为 Buffer
对象拉出,则会被不正确地解码。
readable.unpipe([destination])
destination
<stream.Writable> 要移除管道的可写流。- 返回: <this>
readable.unpipe()
方法解绑之前使用 stream.pipe()
方法绑定的可写流。
如果没有指定 destination
, 则解绑所有管道.
如果指定了 destination
, 但它没有建立管道,则不起作用.
readable.unshift(chunk[, encoding])
chunk
<Buffer> | <Uint8Array> | <string> | <null> | <any> 要推回可读队列的数据块。 对于非对象模式的流,chunk
必须是字符串、Buffer
、Uint8Array
或null
。 对于对象模式的流,chunk
可以是任何 JavaScript 值。encoding
<string> 字符串块的编码。 必须是有效的Buffer
编码,例如'utf8'
或'ascii'
。
将 chunk
作为 null
传递信号表示流的末尾(EOF),其行为与 readable.push(null)
相同,之后不能再写入数据。 EOF 信号会被放在 buffer 的末尾,任何缓冲的数据仍将会被刷新。
readable.unshift()
方法将数据块推回内部缓冲。 可用于以下情景:正被消费中的流需要将一些已经被拉出的数据重置为未消费状态,以便这些数据可以传给其他方。
触发 'end'
事件或抛出运行时错误之后,不能再调用 stream.unshift()
方法。
使用 stream.unshift()
的开发者可以考虑切换到 Transform
流。 详见用于实现流的API。
与 stream.push(chunk)
不同, stream.unshift(chunk)
不会通过重置流的内部读取状态来结束读取过程。 如果在读取期间调用 readable.unshift()
(即从自定义的流上的 stream._read()
实现中调用),则会导致意外结果。 在使用立即的 stream.push('')
调用 readable.unshift()
之后,将适当地重置读取状态,但最好在执行读取的过程中避免调用 readable.unshift()
。
readable.wrap(stream)
在 Node.js v0.10 之前,流没有实现当前定义的所有的流模块 API。(详见兼容性)
当使用老版本的 Node.js 时,只能触发 'data'
事件或调用 stream.pause()
方法,可以使用 readable.wrap()
创建老版本的流作为数据源。
现在几乎无需使用 readable.wrap()
,该方法主要用于老版本的 Node.js 应用和库。
readable[Symbol.asyncIterator]()
返回: <AsyncIterator> 用于完全地消费流。
如果循环以 break
或 throw
终止,则流将会被销毁。 换句话说,迭代流将完全地消费流。 将以大小等于 highWaterMark
选项的块读取流。 在上面的代码示例中,如果文件的数据少于 64kb,则数据将位于单个块中,因为没有为 fs.createReadStream()
提供 highWaterMark
选项。
双工流与转换流
stream.Duplex 类
双工流(Duplex)是同时实现了 Readable
和 Writable
接口的流。
Duplex
流的例子包括:
stream.Transform 类
转换流(Transform)是一种 Duplex
流,但它的输出与输入是相关联的。 与 Duplex
流一样, Transform
流也同时实现了 Readable
和 Writable
接口。
Transform
流的例子包括:
transform.destroy([error])
销毁流,并可选地触发 'error'
事件。 调用该方法后,transform 流会释放全部内部资源。 实现者不应该重写此方法,而应该实现 readable._destroy()
。 Transform
流的 _destroy()
方法的默认实现会触发 'close'
事件,除非 emitClose
被设置为 false
。
stream.finished(stream[, options], callback)
stream
<Stream> 可读和/或可写流。-
options
<Object> callback
<Function> 带有可选错误参数的回调函数。- 返回: <Function> 清理函数,它会移除所有已注册的监听器。
当流不再可读、可写、或遇到错误、或过早关闭事件时,则该函数会获得通知。
stream.pipeline(...streams, callback)
...streams
<Stream> 要使用管道传送的两个或多个流。-
callback
<Function> 当管道完全地完成时调用。err
<Error>
一个模块方法,使用管道传送多个流,并转发错误和正确地清理,当管道完成时提供回调。
stream.pipeline()
将会在所有的流上调用 stream.destroy(err)
,除了:
- 已触发
'end'
或'close'
的Readable
流。 - 已触发
'finish'
或'close'
的Writable
流。
在调用 callback
之后, stream.pipeline()
会将悬挂的事件监听器留在流上。 在失败后重新使用流的情况下,这可能导致事件监听器泄漏和误吞的错误。
stream.Readable.from(iterable, [options])
iterable
<Iterable> 实现Symbol.asyncIterator
或Symbol.iterator
可迭代协议的对象。options
<Object> 提供给new stream.Readable([options])
的选项。 默认情况下,Readable.from()
会将options.objectMode
设置为true
,除非通过将options.objectMode
设置为false
显式地选择此选项。- 返回: <stream.Readable>
一个从迭代器中创建可读流的实用方法。
const { Readable } = require('stream');