@@ -321,10 +321,17 @@ There are two ways to write data to a stream:
321321 up front or can be expressed as an iterable.
322322* ** Writer** β access [ ` stream.writer ` ] [ ] to push data incrementally. The
323323 writer exposes synchronous methods (` writeSync() ` , ` writevSync() ` ,
324- ` endSync() ` ) that return immediately, as well as async equivalents
325- (` write() ` , ` writev() ` , ` end() ` ) that wait for drain when backpressured.
324+ ` endSync() ` ) that return immediately, as well as asynchronous counterparts
325+ (` write() ` , ` writev() ` , ` end() ` ). The asynchronous ` write() ` and ` writev() `
326+ methods use the stream/iter strict backpressure policy: when the write buffer
327+ is full, they reject with ` ERR_INVALID_STATE ` instead of waiting for capacity.
328+ If a drain is already pending, ` end() ` waits for it before closing. Check
329+ ` writer.canWrite ` before writing. To wait for capacity, use ` ondrain() ` from
330+ ` node:stream/iter ` , then retry the write. The stream's ` onblocked ` callback
331+ reports that transport flow control has blocked progress, but does not
332+ signal that writer capacity is available again.
326333 ` writeSync() ` returns ` false ` when the write buffer is full; the caller
327- should wait for drain before retrying.
334+ should wait with ` ondrain() ` before retrying.
328335
329336These two approaches are mutually exclusive for a given stream.
330337
@@ -2322,12 +2329,16 @@ The Writer has the following methods:
23222329
23232330* ` writeSync(chunk) ` β Synchronous write. Returns ` true ` if accepted,
23242331 ` false ` if flow-controlled. Data is NOT accepted on ` false ` .
2325- * ` write(chunk[, options]) ` β Async write with drain wait. ` options.signal `
2326- is checked at entry but not observed during the write.
2332+ * ` write(chunk[, options]) ` β Async write. Rejects with ` ERR_INVALID_STATE `
2333+ when the stream is flow-controlled rather than waiting for capacity.
2334+ ` options.signal ` is checked at entry but not observed during the write.
23272335* ` writevSync(chunks) ` β Synchronous vectored write. All-or-nothing.
2328- * ` writev(chunks[, options]) ` β Async vectored write.
2336+ * ` writev(chunks[, options]) ` β Async vectored write. Rejects with
2337+ ` ERR_INVALID_STATE ` when the stream is flow-controlled rather than waiting
2338+ for capacity.
23292339* ` endSync() ` β Synchronous close. Returns total bytes or ` -1 ` .
2330- * ` end([options]) ` β Async close.
2340+ * ` end([options]) ` β Async close. If a drain is already pending, waits for it
2341+ before closing.
23312342* ` fail(reason) ` β Errors the stream (sends ` RESET_STREAM ` to peer).
23322343 When ` reason ` is a [ ` QuicError ` ] [ ] , its [ ` error.errorCode ` ] [ ] is used
23332344 as the wire code on the resulting ` RESET_STREAM ` frame; otherwise
@@ -2337,7 +2348,20 @@ The Writer has the following methods:
23372348 See [ ` stream.destroy() ` ] [ ] for a full-stream abort that also resets
23382349 the readable side via ` STOP_SENDING ` .
23392350* ` canWrite ` β ` true ` if writes will be accepted, ` false ` if at capacity,
2340- or ` null ` if closed/errored.
2351+ or ` null ` if closed/errored. When ` writeSync() ` returns ` false ` , use
2352+ ` ondrain() ` from ` node:stream/iter ` to wait before retrying. If ` ondrain() `
2353+ returns ` null ` , no drain wait is available and the write should not be
2354+ retried.
2355+
2356+ ``` mjs
2357+ import { ondrain } from ' node:stream/iter' ;
2358+
2359+ while (! writer .writeSync (chunk)) {
2360+ const drain = ondrain (writer);
2361+ if (drain === null ) break ;
2362+ await drain;
2363+ }
2364+ ```
23412365
23422366The bytes from each ` writeSync() ` / ` writevSync() ` / ` write() ` / ` writev() `
23432367input chunk are copied into an internal buffer, so the caller's source
0 commit comments