Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34.2k
lib: initial experimental AbortController implementation#33527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -167,6 +167,18 @@ Enable experimental Source Map V3 support for stack traces. | ||
| Currently, overriding `Error.prepareStackTrace` is ignored when the | ||
| `--enable-source-maps` flag is set. | ||
| ### `--experimental-abortcontroller` | ||
| <!-- YAML | ||
| added: REPLACEME | ||
| changes: | ||
| - version: REPLACEME | ||
| pr-url: https://github.com/nodejs/node/pull/33527 | ||
| description: --experimental-abortcontroller is no longer required. | ||
| --> | ||
| Experimental `AbortController` and `AbortSignal` support is enabled by default. | ||
| Use of this command line flag is no longer required. | ||
jasnell marked this conversation as resolved. Outdated Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| ### `--experimental-import-meta-resolve` | ||
| <!-- YAML | ||
| added: | ||
| @@ -1209,6 +1221,7 @@ Node.js options that are allowed are: | ||
| * `--disable-proto` | ||
| * `--enable-fips` | ||
| * `--enable-source-maps` | ||
| * `--experimental-abortcontroller` | ||
| * `--experimental-import-meta-resolve` | ||
| * `--experimental-json-modules` | ||
| * `--experimental-loader` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -17,6 +17,99 @@ The objects listed here are specific to Node.js. There are [built-in objects][] | ||
| that are part of the JavaScript language itself, which are also globally | ||
| accessible. | ||
| ## Class: `AbortController` | ||
| <!--YAML | ||
| added: REPLACEME | ||
| --> | ||
| > Stability: 1 - Experimental | ||
| <!-- type=global --> | ||
| A utility class used to signal cancelation in selected `Promise`-based APIs. | ||
| The API is based on the Web API [`AbortController`][]. | ||
| ```js | ||
| const ac = new AbortController(); | ||
| ac.signal.addEventListener('abort', () => console.log('Aborted!'), | ||
| {once: true }); | ||
| ac.abort(); | ||
| console.log(ac.signal.aborted); // Prints True | ||
| ``` | ||
| ### `abortController.abort()` | ||
| <!-- YAML | ||
| added: REPLACEME | ||
| --> | ||
| Triggers the abort signal, causing the `abortController.signal` to emit | ||
| the `'abort'` event. | ||
| ### `abortController.signal` | ||
| <!-- YAML | ||
| added: REPLACEME | ||
| --> | ||
| * Type:{AbortSignal} | ||
| ### Class: `AbortSignal extends EventTarget` | ||
| <!-- YAML | ||
| added: REPLACEME | ||
| --> | ||
| The `AbortSignal` is used to notify observers when the | ||
| `abortController.abort()` method is called. | ||
| #### Event: `'abort'` | ||
| <!-- YAML | ||
| added: REPLACEME | ||
| --> | ||
| The `'abort'` event is emitted when the `abortController.abort()` method | ||
| is called. The callback is invoked with a single object argument with a | ||
| single `type` propety set to `'abort'`: | ||
| ```js | ||
| const ac = new AbortController(); | ||
| // Use either the onabort property... | ||
| ac.signal.onabort = () => console.log('aborted!'); | ||
jasnell marked this conversation as resolved. Outdated Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| // Or the EventTarget API... | ||
| ac.signal.addEventListener('abort', (event) =>{ | ||
| console.log(event.type); // Prints 'abort' | ||
| },{once: true }); | ||
| ac.abort(); | ||
| ``` | ||
| The `AbortController` with which the `AbortSignal` is associated will only | ||
| ever trigger the `'abort'` event once. Any event listeners attached to the | ||
| `AbortSignal` *should* use the `{once: true }` option (or, if using the | ||
| `EventEmitter` APIs to attach a listener, use the `once()` method) to ensure | ||
| that the event listener is removed as soon as the `'abort'` event is handled. | ||
| Failure to do so may result in memory leaks. | ||
| #### `abortSignal.aborted` | ||
| <!-- YAML | ||
| added: REPLACEME | ||
| --> | ||
| * Type:{boolean} True after the `AbortController` has been aborted. | ||
| #### `abortSignal.onabort` | ||
| <!-- YAML | ||
| added: REPLACEME | ||
| --> | ||
| * Type:{Function} | ||
| An optional callback function that may be set by user code to be notified | ||
| when the `abortController.abort()` function has been called. | ||
| ## Class: `Buffer` | ||
| <!-- YAML | ||
| added: v0.1.103 | ||
| @@ -226,6 +319,7 @@ The object that acts as the namespace for all W3C | ||
| [WebAssembly][webassembly-org] related functionality. See the | ||
| [Mozilla Developer Network][webassembly-mdn] for usage and compatibility. | ||
| [`AbortController`]: https://developer.mozilla.org/en-US/docs/Web/API/AbortController | ||
| [`TextDecoder`]: util.html#util_class_util_textdecoder | ||
| [`TextEncoder`]: util.html#util_class_util_textencoder | ||
| [`URLSearchParams`]: url.html#url_class_urlsearchparams | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| 'use strict' | ||
| // Modeled very closely on the AbortController implementation | ||
| // in https://github.com/mysticatea/abort-controller (MIT license) | ||
| ||
| const{ | ||
| Object, | ||
| Symbol, | ||
| } = primordials; | ||
| const{ | ||
| EventTarget, | ||
| Event | ||
| } = require('internal/event_target'); | ||
| const{ | ||
| customInspectSymbol, | ||
| emitExperimentalWarning | ||
| } = require('internal/util'); | ||
| const{inspect } = require('internal/util/inspect'); | ||
| const kAborted = Symbol('kAborted'); | ||
| function customInspect(self, obj, depth, options){ | ||
| if (depth < 0) | ||
| return self; | ||
| const opts = Object.assign({}, options,{ | ||
| depth: options.depth === null ? null : options.depth - 1 | ||
| }); | ||
| return `${self.constructor.name} ${inspect(obj, opts)}`; | ||
| } | ||
| class AbortSignal extends EventTarget{ | ||
| get aborted(){return !!this[kAborted]} | ||
| [customInspectSymbol](depth, options){ | ||
| return customInspect(this,{ | ||
| aborted: this.aborted | ||
| }, depth, options); | ||
| } | ||
| } | ||
| Object.defineProperties(AbortSignal.prototype,{ | ||
| aborted:{enumerable: true } | ||
| }); | ||
| function abortSignal(signal){ | ||
| if (signal[kAborted]) return; | ||
| signal[kAborted] = true; | ||
| const event = new Event('abort'); | ||
| if (typeof signal.onabort === 'function'){ | ||
| signal.onabort(event); | ||
| } | ||
| signal.dispatchEvent(event); | ||
| } | ||
jasnell marked this conversation as resolved. Outdated Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| class AbortController{ | ||
| #signal = new AbortSignal(); | ||
| constructor(){ | ||
| emitExperimentalWarning('AbortController'); | ||
| } | ||
| get signal(){return this.#signal} | ||
| abort(){abortSignal(this.#signal)} | ||
| [customInspectSymbol](depth, options){ | ||
| return customInspect(this,{ | ||
| signal: this.signal | ||
| }, depth, options); | ||
| } | ||
jasnell marked this conversation as resolved. Outdated Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| Object.defineProperties(AbortController.prototype,{ | ||
| signal:{enumerable: true }, | ||
| abort:{enumerable: true } | ||
| }); | ||
| module.exports ={ | ||
| AbortController, | ||
| AbortSignal, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -133,6 +133,13 @@ if (!config.noBrowserGlobals){ | ||
| // https://encoding.spec.whatwg.org/#textdecoder | ||
| exposeInterface(global, 'TextDecoder', TextDecoder); | ||
| const{ | ||
| AbortController, | ||
| AbortSignal, | ||
| } = require('internal/abort_controller'); | ||
| exposeInterface(global, 'AbortController', AbortController); | ||
jasnell marked this conversation as resolved. Outdated Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| exposeInterface(global, 'AbortSignal', AbortSignal); | ||
| // https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope | ||
| const timers = require('timers'); | ||
| defineOperation(global, 'clearInterval', timers.clearInterval); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Flags: --no-warnings | ||
| 'use strict' | ||
| const common = require('../common'); | ||
| const{ok, strictEqual } = require('assert'); | ||
| { | ||
| const ac = new AbortController(); | ||
| ok(ac.signal); | ||
| ac.signal.onabort = common.mustCall((event) =>{ | ||
| ok(event); | ||
| strictEqual(event.type, 'abort'); | ||
| }); | ||
| ac.signal.addEventListener('abort', common.mustCall((event) =>{ | ||
| ok(event); | ||
| strictEqual(event.type, 'abort'); | ||
| }),{once: true }); | ||
| ac.abort(); | ||
| ac.abort(); | ||
| ok(ac.signal.aborted); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -20,6 +20,7 @@ const expectedModules = new Set([ | ||
| 'Internal Binding module_wrap', | ||
| 'Internal Binding native_module', | ||
| 'Internal Binding options', | ||
| 'Internal Binding performance', | ||
| 'Internal Binding process_methods', | ||
| 'Internal Binding report', | ||
| 'Internal Binding string_decoder', | ||
| @@ -30,9 +31,11 @@ const expectedModules = new Set([ | ||
| 'Internal Binding types', | ||
| 'Internal Binding url', | ||
| 'Internal Binding util', | ||
| 'NativeModule async_hooks', | ||
| 'NativeModule buffer', | ||
| 'NativeModule events', | ||
| 'NativeModule fs', | ||
| 'NativeModule internal/abort_controller', | ||
| 'NativeModule internal/assert', | ||
| 'NativeModule internal/async_hooks', | ||
| 'NativeModule internal/bootstrap/pre_execution', | ||
| @@ -42,9 +45,11 @@ const expectedModules = new Set([ | ||
| 'NativeModule internal/constants', | ||
| 'NativeModule internal/encoding', | ||
| 'NativeModule internal/errors', | ||
| 'NativeModule internal/event_target', | ||
| 'NativeModule internal/fixed_queue', | ||
| 'NativeModule internal/fs/dir', | ||
| 'NativeModule internal/fs/utils', | ||
| 'NativeModule internal/histogram', | ||
jasnell marked this conversation as resolved. Outdated Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| 'NativeModule internal/idna', | ||
| 'NativeModule internal/linkedlist', | ||
| 'NativeModule internal/modules/run_main', | ||
| @@ -81,8 +86,10 @@ const expectedModules = new Set([ | ||
| 'NativeModule internal/validators', | ||
| 'NativeModule internal/vm/module', | ||
| 'NativeModule path', | ||
| 'NativeModule perf_hooks', | ||
| 'NativeModule timers', | ||
| 'NativeModule url', | ||
| 'NativeModule util', | ||
| 'NativeModule vm', | ||
| ]); | ||
Uh oh!
There was an error while loading. Please reload this page.