diff --git a/doc/api/quic.md b/doc/api/quic.md index d90b1b938bd2..c4b22a94af9c 100644 --- a/doc/api/quic.md +++ b/doc/api/quic.md @@ -343,6 +343,10 @@ 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()`. +Consuming a stream is what returns flow-control credit to the peer, so a +stream whose payload is not wanted should still be read to completion. Use +`Stream.drain()` to read the stream without retaining any of it. + ### Datagrams In addition to streams, QUIC supports unreliable datagrams ([RFC 9221][]) for diff --git a/doc/api/stream_iter.md b/doc/api/stream_iter.md index c1ebacd3dfad..a2b002cf9af1 100644 --- a/doc/api/stream_iter.md +++ b/doc/api/stream_iter.md @@ -1025,6 +1025,81 @@ added: Synchronous version of [`bytes()`][]. +### `drain(source[, options])` + + + +* `source` {AsyncIterable|Iterable} whose chunks must be {Uint8Array\[]} +* `options` {Object} + * `signal` {AbortSignal} + * `limit` {number} Maximum number of bytes to consume. If the total bytes + read exceeds limit, an `ERR_OUT_OF_RANGE` error is thrown +* Returns: {Promise} Fulfills with `undefined`. + +Read a source to completion, discarding every chunk. Unlike the other +consumers, `drain()` retains nothing. Memory tops-out at a single batch no +matter how much data the source produces. + +Use this to consume a stream when the content doesn't matter. For example, A +QUIC stream only returns flow-control credit to the peer as its data is +consumed, so a receiver that does not want the payload must still read it to +completion. + +If the source errors part-way through, the returned promise rejects with that +error. + +There is no default `limit`. `drain()` reads until the source is exhausted +unless a limit is specified. When a limit is configured and the source exceeds +it, the promise rejects and the source is cancelled. A partial drain is never +reported as success. + +```mjs +import { drain, from, pull, tap } from 'node:stream/iter'; + +// Count the bytes flowing through a stream without retaining any of them. +let bytesSeen = 0; +const counter = tap((chunks) => { + for (const chunk of chunks) bytesSeen += chunk.byteLength; +}); + +await drain(pull(from('hello world'), counter)); +console.log(bytesSeen); // 11 +``` + +```cjs +const { drain, from, pull, tap } = require('node:stream/iter'); + +async function run() { + // Count the bytes flowing through a stream without retaining any of them. + let bytesSeen = 0; + const counter = tap((chunks) => { + for (const chunk of chunks) bytesSeen += chunk.byteLength; + }); + + await drain(pull(from('hello world'), counter)); + console.log(bytesSeen); // 11 +} + +run().catch(console.error); +``` + +### `drainSync(source[, options])` + + + +* `source` {Iterable} whose chunks must be {Uint8Array\[]} +* `options` {Object} + * `limit` {number} Maximum number of bytes to consume. If the total bytes + read exceeds limit, an `ERR_OUT_OF_RANGE` error is thrown +* Returns: {undefined} + +Synchronous version of [`drain()`][]. Throws `ERR_INVALID_ARG_TYPE` if `source` +is not synchronously iterable. + ### `text(source[, options])`