流
🌐 Streams
流是 QUIC 中主要的数据承载抽象。一旦会话建立,流可以由本地端点或远程端点发起。
🌐 Streams are the primary data-carrying abstraction in QUIC. A stream can be initiated by either the local endpoint or the remote peer once a session is established.
数据流可以是双向的(数据在两个方向流动)或单向的(数据只在一个方向流动)。quic 模块提供了用于创建每种类型的独立 API:session.createBidirectionalStream() 和 session.createUnidirectionalStream()。由远程对端发起的数据流会通过 session.onstream 回调传递。当协商的应用协议支持流级回调(例如 HTTP/3)并且配置了 onheaders 回调时,传入的数据流可以完全通过它进行消费,注册 onstream 则是可选的。
🌐 Streams can be either bidirectional (data flows in both directions) or
unidirectional (data flows in only one direction). The quic module provides
separate APIs for creating each kind:
session.createBidirectionalStream() and
session.createUnidirectionalStream(). Streams initiated by a remote
peer are delivered via the session.onstream callback. When the
negotiated application protocol supports the stream-level callbacks (e.g.
HTTP/3) and an onheaders callback is configured, incoming streams can
instead be consumed entirely through it and registering onstream is
optional.
有两种方式可以将数据写入流:
🌐 There are two ways to write data to a stream:
- 主体来源 — 在创建流时传入
body选项(或调用stream.setBody())。主体可以是字符串、ArrayBuffer、ArrayBufferView、Blob、FileHandle、AsyncIterable、同步的Iterable,或解析为这些任意类型的Promise。一个null主体会立即关闭可写端。当数据已经可用或可以表示为可迭代对象时,这是最简单的方法。 - Writer — 使用
stream.writer以增量方式推送数据。该 writer 提供同步方法(writeSync()、writevSync()、endSync()),会立即返回,也有异步对应方法(write()、writev()、end())。异步的write()和writev()方法遵循流/迭代严格的背压策略:当写入缓冲区已满时,它们会返回ERR_INVALID_STATE拒绝,而不会等待容量。如果有排队的 drain,end()会在关闭前先等待它。写入前检查writer.canWrite。要等待容量,可以使用来自node:stream/iter的ondrain(),然后重试写入。流的onblocked回调会报告传输流控阻塞了进度,但不会表示 writer 容量再次可用。writeSync()在写入缓冲区满时返回false;调用方应使用ondrain()等待再重试。
对于给定的流,这两种方法是互斥的。
🌐 These two approaches are mutually exclusive for a given stream.
读取是通过将流作为异步可迭代对象进行迭代来完成的。每次迭代都会产生一批 Uint8Array 块:
🌐 Reading is done by iterating the stream as an async iterable. Each iteration
yields a batch of Uint8Array chunks:
for await (const chunks of stream) {
for (const chunk of chunks) {
// Process each Uint8Array chunk
}
} 每个流只能获取一个异步迭代器。该流也兼容 node:stream/iter 工具,例如 Stream.bytes()、Stream.text() 和 Stream.pipeTo()。
🌐 Only one async iterator can be obtained per stream. The stream is also
compatible with node:stream/iter utilities such as Stream.bytes(),
Stream.text(), and Stream.pipeTo().