| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1938,6 +1938,9 @@ method. | |||
| 1938 | 1938 | #### `new stream.Writable([options])` | |
| 1939 | 1939 | <!-- YAML | |
| 1940 | 1940 | changes: | |
| 1941 | + - version: REPLACEME | ||
| 1942 | + pr-url: https://github.com/nodejs/node/pull/36431 | ||
| 1943 | + description: support passing in an AbortSignal. | ||
| 1941 | 1944 | - version: v14.0.0 | |
| 1942 | 1945 | pr-url: https://github.com/nodejs/node/pull/30623 | |
| 1943 | 1946 | description: Change `autoDestroy` option default to `true`. | |
@@ -1985,6 +1988,7 @@ changes: | |||
| 1985 | 1988 | [`stream._construct()`][writable-_construct] method. | |
| 1986 | 1989 | * `autoDestroy` {boolean} Whether this stream should automatically call | |
| 1987 | 1990 | `.destroy()` on itself after ending. **Default:** `true`. | |
| 1991 | + * `signal` {AbortSignal} A signal representing possible cancellation. | ||
| 1988 | 1992 | ||
| 1989 | 1993 | <!-- eslint-disable no-useless-constructor --> | |
| 1990 | 1994 | ```js | |
@@ -2028,6 +2032,27 @@ const myWritable = new Writable({ | |||
| 2028 | 2032 | }); | |
| 2029 | 2033 | ``` | |
| 2030 | 2034 | ||
| 2035 | + Calling `abort` on the `AbortController` corresponding to the passed | ||
| 2036 | + `AbortSignal` will behave the same way as calling `.destroy(new AbortError())` | ||
| 2037 | + on the writeable stream. | ||
| 2038 | + | ||
| 2039 | + ```js | ||
| 2040 | + const { Writable } = require('stream'); | ||
| 2041 | + | ||
| 2042 | + const controller = new AbortController(); | ||
| 2043 | + const myWritable = new Writable({ | ||
| 2044 | + write(chunk, encoding, callback) { | ||
| 2045 | + // ... | ||
| 2046 | + }, | ||
| 2047 | + writev(chunks, callback) { | ||
| 2048 | + // ... | ||
| 2049 | + }, | ||
| 2050 | + signal: controller.signal | ||
| 2051 | + }); | ||
| 2052 | + // Later, abort the operation closing the stream | ||
| 2053 | + controller.abort(); | ||
| 2054 | + | ||
| 2055 | + ``` | ||
| 2031 | 2056 | #### `writable._construct(callback)` | |
| 2032 | 2057 | <!-- YAML | |
| 2033 | 2058 | added: v15.0.0 | |
@@ -2276,6 +2301,9 @@ constructor and implement the [`readable._read()`][] method. | |||
| 2276 | 2301 | #### `new stream.Readable([options])` | |
| 2277 | 2302 | <!-- YAML | |
| 2278 | 2303 | changes: | |
| 2304 | + - version: REPLACEME | ||
| 2305 | + pr-url: https://github.com/nodejs/node/pull/36431 | ||
| 2306 | + description: support passing in an AbortSignal. | ||
| 2279 | 2307 | - version: v14.0.0 | |
| 2280 | 2308 | pr-url: https://github.com/nodejs/node/pull/30623 | |
| 2281 | 2309 | description: Change `autoDestroy` option default to `true`. | |
@@ -2306,6 +2334,7 @@ changes: | |||
| 2306 | 2334 | [`stream._construct()`][readable-_construct] method. | |
| 2307 | 2335 | * `autoDestroy` {boolean} Whether this stream should automatically call | |
| 2308 | 2336 | `.destroy()` on itself after ending. **Default:** `true`. | |
| 2337 | + * `signal` {AbortSignal} A signal representing possible cancellation. | ||
| 2309 | 2338 | ||
| 2310 | 2339 | <!-- eslint-disable no-useless-constructor --> | |
| 2311 | 2340 | ```js | |
@@ -2346,6 +2375,23 @@ const myReadable = new Readable({ | |||
| 2346 | 2375 | }); | |
| 2347 | 2376 | ``` | |
| 2348 | 2377 | ||
| 2378 | + Calling `abort` on the `AbortController` corresponding to the passed | ||
| 2379 | + `AbortSignal` will behave the same way as calling `.destroy(new AbortError())` | ||
| 2380 | + on the readable created. | ||
| 2381 | + | ||
| 2382 | + ```js | ||
| 2383 | + const fs = require('fs'); | ||
| 2384 | + const controller = new AbortController(); | ||
| 2385 | + const read = new Readable({ | ||
| 2386 | + read(size) { | ||
| 2387 | + // ... | ||
| 2388 | + }, | ||
| 2389 | + signal: controller.signal | ||
| 2390 | + }); | ||
| 2391 | + // Later, abort the operation closing the stream | ||
| 2392 | + controller.abort(); | ||
| 2393 | + ``` | ||
| 2394 | + | ||
| 2349 | 2395 | #### `readable._construct(callback)` | |
| 2350 | 2396 | <!-- YAML | |
| 2351 | 2397 | added: v15.0.0 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,12 +9,11 @@ const eos = require('internal/streams/end-of-stream'); | |||
| 9 | 9 | const { ERR_INVALID_ARG_TYPE } = codes; | |
| 10 | 10 | ||
| 11 | 11 | // This method is inlined here for readable-stream | |
| 12 | + // It also does not allow for signal to not exist on the steam | ||
| 12 | 13 | // https://github.com/nodejs/node/pull/36061#discussion_r533718029 | |
| 13 | 14 | const validateAbortSignal = (signal, name) => { | |
| 14 | - if (signal !== undefined && | ||
| 15 | - (signal === null || | ||
| 16 | - typeof signal !== 'object' || | ||
| 17 | - !('aborted' in signal))) { | ||
| 15 | + if (typeof signal !== 'object' || | ||
| 16 | + !('aborted' in signal)) { | ||
| 18 | 17 | throw new ERR_INVALID_ARG_TYPE(name, 'AbortSignal', signal); | |
| 19 | 18 | } | |
| 20 | 19 | }; | |
@@ -23,11 +22,17 @@ function isStream(obj) { | |||
| 23 | 22 | return !!(obj && typeof obj.pipe === 'function'); | |
| 24 | 23 | } | |
| 25 | 24 | ||
| 26 | - module.exports = function addAbortSignal(signal, stream) { | ||
| 25 | + module.exports.addAbortSignal = function addAbortSignal(signal, stream) { | ||
| 27 | 26 | validateAbortSignal(signal, 'signal'); | |
| 28 | 27 | if (!isStream(stream)) { | |
| 29 | 28 | throw new ERR_INVALID_ARG_TYPE('stream', 'stream.Stream', stream); | |
| 30 | 29 | } | |
| 30 | + return module.exports.addAbortSignalNoValidate(signal, stream); | ||
| 31 | + }; | ||
| 32 | + module.exports.addAbortSignalNoValidate = function(signal, stream) { | ||
| 33 | + if (typeof signal !== 'object' || !('aborted' in signal)) { | ||
| 34 | + return stream; | ||
| 35 | + } | ||
| 31 | 36 | const onAbort = () => { | |
| 32 | 37 | stream.destroy(new AbortError()); | |
| 33 | 38 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,6 +41,10 @@ const EE = require('events'); | |||
| 41 | 41 | const { Stream, prependListener } = require('internal/streams/legacy'); | |
| 42 | 42 | const { Buffer } = require('buffer'); | |
| 43 | 43 | ||
| 44 | + const { | ||
| 45 | + addAbortSignalNoValidate, | ||
| 46 | + } = require('internal/streams/add-abort-signal'); | ||
| 47 | + | ||
| 44 | 48 | let debug = require('internal/util/debuglog').debuglog('stream', (fn) => { | |
| 45 | 49 | debug = fn; | |
| 46 | 50 | }); | |
@@ -192,6 +196,8 @@ function Readable(options) { | |||
| 192 | 196 | ||
| 193 | 197 | if (typeof options.construct === 'function') | |
| 194 | 198 | this._construct = options.construct; | |
| 199 | + if (options.signal && !isDuplex) | ||
| 200 | + addAbortSignalNoValidate(options.signal, this); | ||
| 195 | 201 | } | |
| 196 | 202 | ||
| 197 | 203 | Stream.call(this, options); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,6 +41,11 @@ const EE = require('events'); | |||
| 41 | 41 | const Stream = require('internal/streams/legacy').Stream; | |
| 42 | 42 | const { Buffer } = require('buffer'); | |
| 43 | 43 | const destroyImpl = require('internal/streams/destroy'); | |
| 44 | + | ||
| 45 | + const { | ||
| 46 | + addAbortSignalNoValidate, | ||
| 47 | + } = require('internal/streams/add-abort-signal'); | ||
| 48 | + | ||
| 44 | 49 | const { | |
| 45 | 50 | getHighWaterMark, | |
| 46 | 51 | getDefaultHighWaterMark | |
@@ -263,6 +268,8 @@ function Writable(options) { | |||
| 263 | 268 | ||
| 264 | 269 | if (typeof options.construct === 'function') | |
| 265 | 270 | this._construct = options.construct; | |
| 271 | + if (options.signal) | ||
| 272 | + addAbortSignalNoValidate(options.signal, this); | ||
| 266 | 273 | } | |
| 267 | 274 | ||
| 268 | 275 | Stream.call(this, options); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -43,7 +43,8 @@ Stream.Duplex = require('internal/streams/duplex'); | |||
| 43 | 43 | Stream.Transform = require('internal/streams/transform'); | |
| 44 | 44 | Stream.PassThrough = require('internal/streams/passthrough'); | |
| 45 | 45 | Stream.pipeline = pipeline; | |
| 46 | - Stream.addAbortSignal = require('internal/streams/add-abort-signal'); | ||
| 46 | + const { addAbortSignal } = require('internal/streams/add-abort-signal'); | ||
| 47 | + Stream.addAbortSignal = addAbortSignal; | ||
| 47 | 48 | Stream.finished = eos; | |
| 48 | 49 | ||
| 49 | 50 | function lazyLoadPromises() { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -238,3 +238,20 @@ const assert = require('assert'); | |||
| 238 | 238 | }); | |
| 239 | 239 | duplex.on('close', common.mustCall()); | |
| 240 | 240 | } | |
| 241 | + { | ||
| 242 | + // Check abort signal | ||
| 243 | + const controller = new AbortController(); | ||
| 244 | + const { signal } = controller; | ||
| 245 | + const duplex = new Duplex({ | ||
| 246 | + write(chunk, enc, cb) { cb(); }, | ||
| 247 | + read() {}, | ||
| 248 | + signal, | ||
| 249 | + }); | ||
| 250 | + let count = 0; | ||
| 251 | + duplex.on('error', common.mustCall((e) => { | ||
| 252 | + assert.strictEqual(count++, 0); // Ensure not called twice | ||
| 253 | + assert.strictEqual(e.name, 'AbortError'); | ||
| 254 | + })); | ||
| 255 | + duplex.on('close', common.mustCall()); | ||
| 256 | + controller.abort(); | ||
| 257 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -284,6 +284,22 @@ const assert = require('assert'); | |||
| 284 | 284 | read.on('data', common.mustNotCall()); | |
| 285 | 285 | } | |
| 286 | 286 | ||
| 287 | + { | ||
| 288 | + const controller = new AbortController(); | ||
| 289 | + const read = new Readable({ | ||
| 290 | + signal: controller.signal, | ||
| 291 | + read() { | ||
| 292 | + this.push('asd'); | ||
| 293 | + }, | ||
| 294 | + }); | ||
| 295 | + | ||
| 296 | + read.on('error', common.mustCall((e) => { | ||
| 297 | + assert.strictEqual(e.name, 'AbortError'); | ||
| 298 | + })); | ||
| 299 | + controller.abort(); | ||
| 300 | + read.on('data', common.mustNotCall()); | ||
| 301 | + } | ||
| 302 | + | ||
| 287 | 303 | { | |
| 288 | 304 | const controller = new AbortController(); | |
| 289 | 305 | const read = addAbortSignal(controller.signal, new Readable({ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -431,3 +431,18 @@ const assert = require('assert'); | |||
| 431 | 431 | write.write('asd'); | |
| 432 | 432 | ac.abort(); | |
| 433 | 433 | } | |
| 434 | + | ||
| 435 | + { | ||
| 436 | + const ac = new AbortController(); | ||
| 437 | + const write = new Writable({ | ||
| 438 | + signal: ac.signal, | ||
| 439 | + write(chunk, enc, cb) { cb(); } | ||
| 440 | + }); | ||
| 441 | + | ||
| 442 | + write.on('error', common.mustCall((e) => { | ||
| 443 | + assert.strictEqual(e.name, 'AbortError'); | ||
| 444 | + assert.strictEqual(write.destroyed, true); | ||
| 445 | + })); | ||
| 446 | + write.write('asd'); | ||
| 447 | + ac.abort(); | ||
| 448 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments