From 7fd96063001d381637a04a0c6affd7441905df54 Mon Sep 17 00:00:00 2001 From: shirakaba <14055146+shirakaba@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:37:48 +0900 Subject: [PATCH] drop support for transferable AbortControllers/AbortSignals Seems it's a non-standard feature. Dropping because it would still have required users to do extra work like providing their own MessageChannel implementation to override the included one. It's a feature that requires runtime integration, so I can only provide a basis and not a full implementation. https://github.com/whatwg/dom/issues/948 --- src/abort-controller.js | 120 +--------------------------------------- src/js-transferable.js | 56 ------------------- src/message-channel.js | 26 --------- 3 files changed, 1 insertion(+), 201 deletions(-) delete mode 100644 src/js-transferable.js delete mode 100644 src/message-channel.js diff --git a/src/abort-controller.js b/src/abort-controller.js index 806d2af..25748c7 100644 --- a/src/abort-controller.js +++ b/src/abort-controller.js @@ -49,23 +49,6 @@ const { ERR_METHOD_NOT_IMPLEMENTED, } = codes; -import { - kDeserialize, - kTransfer, - kTransferList, - markTransferMode, -} from './js-transferable.js'; -import { MessageChannel as NoOpMessageChannel } from './message-channel.js'; - -function lazyMessageChannel() { - const MessageChannel = globalThis.MessageChannel ?? NoOpMessageChannel; - return new MessageChannel(); -} - -function lazyMarkTransferMode(obj, cloneable, transferable) { - markTransferMode(obj, cloneable, transferable); -} - const clearTimeoutRegistry = new SafeFinalizationRegistry( globalThis.clearTimeout, ); @@ -73,9 +56,7 @@ const gcPersistentSignals = new SafeSet(); const kAborted = Symbol('kAborted'); const kReason = Symbol('kReason'); -const kCloneData = Symbol('kCloneData'); const kTimeout = Symbol('kTimeout'); -const kMakeTransferable = Symbol('kMakeTransferable'); const kComposite = Symbol('kComposite'); const kSourceSignals = Symbol('kSourceSignals'); const kDependantSignals = Symbol('kDependantSignals'); @@ -259,73 +240,8 @@ export class AbortSignal extends EventTarget { gcPersistentSignals.delete(this); } } - - [kTransfer]() { - validateThisAbortSignal(this); - const aborted = this.aborted; - if (aborted) { - const reason = this.reason; - return { - data: { aborted, reason }, - deserializeInfo: 'internal/abort_controller:ClonedAbortSignal', - }; - } - - const { port1, port2 } = this[kCloneData]; - this[kCloneData] = undefined; - - this.addEventListener( - 'abort', - () => { - port1.postMessage(this.reason); - port1.close(); - }, - { once: true }, - ); - - return { - data: { port: port2 }, - deserializeInfo: 'internal/abort_controller:ClonedAbortSignal', - }; - } - - [kTransferList]() { - if (!this.aborted) { - const { port1, port2 } = lazyMessageChannel(); - port1.unref(); - port2.unref(); - this[kCloneData] = { - port1, - port2, - }; - return [port2]; - } - return []; - } - - [kDeserialize]({ aborted, reason, port }) { - if (aborted) { - this[kAborted] = aborted; - this[kReason] = reason; - return; - } - - port.onmessage = ({ data }) => { - abortSignal(this, data); - port.close(); - port.onmessage = undefined; - }; - // The receiving port, by itself, should never keep the event loop open. - // The unref() has to be called *after* setting the onmessage handler. - port.unref(); - } } -export function ClonedAbortSignal() { - return createAbortSignal({ transferable: true }); -} -ClonedAbortSignal.prototype[kDeserialize] = () => {}; - ObjectDefineProperties(AbortSignal.prototype, { aborted: kEnumerableProperty, }); @@ -344,26 +260,17 @@ defineEventHandler(AbortSignal.prototype, 'abort'); * @param {{ * aborted? : boolean, * reason? : any, - * transferable? : boolean, * composite? : boolean, * }} [init] * @returns {AbortSignal} */ function createAbortSignal(init = kEmptyObject) { - const { - aborted = false, - reason = undefined, - transferable = false, - composite = false, - } = init; + const { aborted = false, reason = undefined, composite = false } = init; const signal = new EventTarget(); ObjectSetPrototypeOf(signal, AbortSignal.prototype); signal[kAborted] = aborted; signal[kReason] = reason; signal[kComposite] = composite; - if (transferable) { - lazyMarkTransferMode(signal, false, true); - } return signal; } @@ -409,31 +316,6 @@ export class AbortController { options, ); } - - static [kMakeTransferable]() { - const controller = new AbortController(); - controller.#signal = createAbortSignal({ transferable: true }); - return controller; - } -} - -/** - * Enables the AbortSignal to be transferable using structuredClone/postMessage. - * @param {AbortSignal} signal - * @returns {AbortSignal} - */ -export function transferableAbortSignal(signal) { - if (signal?.[kAborted] === undefined) - throw new ERR_INVALID_ARG_TYPE('signal', 'AbortSignal', signal); - lazyMarkTransferMode(signal, false, true); - return signal; -} - -/** - * Creates an AbortController with a transferable AbortSignal - */ -export function transferableAbortController() { - return AbortController[kMakeTransferable](); } /** diff --git a/src/js-transferable.js b/src/js-transferable.js deleted file mode 100644 index 8bac0fb..0000000 --- a/src/js-transferable.js +++ /dev/null @@ -1,56 +0,0 @@ -export const kDeserialize = Symbol('messaging_deserialize_symbol'); -export const kTransfer = Symbol('messaging_transfer_symbol'); -export const kTransferList = Symbol('messaging_transfer_list_symbol'); - -export const kDisallowCloneAndTransfer = Symbol('kDisallowCloneAndTransfer'); -export const kCloneable = Symbol('kCloneable'); -export const kTransferable = Symbol('kTransferable'); -export const transfer_mode_private_symbol = Symbol('node:transfer_mode'); - -/** - * Mark an object as being transferable or customized cloneable in - * `.postMessage()`. - * This should only applied to host objects like Web API interfaces, Node.js' - * built-in objects. - * Objects marked as cloneable and transferable should implement the method - * `@@kClone` and `@@kTransfer` respectively. Method `@@kDeserialize` is - * required to deserialize the data to a new instance. - * - * Example implementation of a cloneable interface (assuming its located in - * `internal/my_interface.js`): - * - * ``` - * class MyInterface { - * constructor(...args) { - * markTransferMode(this, true); - * this.args = args; - * } - * [kDeserialize](data) { - * this.args = data.args; - * } - * [kClone]() { - * return { - * data: { args: this.args }, - * deserializeInfo: 'internal/my_interface:MyInterface', - * } - * } - * } - * - * module.exports = { - * MyInterface, - * }; - * ``` - * @param {object} obj Host objects that can be either cloned or transferred. - * @param {boolean} [cloneable] if the object can be cloned and `@@kClone` is - * implemented. - * @param {boolean} [transferable] if the object can be transferred and - * `@@kTransfer` is implemented. - */ -export function markTransferMode(obj, cloneable = false, transferable = false) { - if ((typeof obj !== 'object' && typeof obj !== 'function') || obj === null) - return; // This object is a primitive and therefore already untransferable. - let mode = kDisallowCloneAndTransfer; - if (cloneable) mode |= kCloneable; - if (transferable) mode |= kTransferable; - obj[transfer_mode_private_symbol] = mode; -} diff --git a/src/message-channel.js b/src/message-channel.js deleted file mode 100644 index 5089adb..0000000 --- a/src/message-channel.js +++ /dev/null @@ -1,26 +0,0 @@ -import { EventTarget } from './event-target'; - -/** - * A dummy no-op MessagePort implementation. - */ -class MessagePort extends EventTarget { - onmessage = null; - onmessageerror = null; - close() {} - postMessage() {} - start() {} -} - -/** - * A dummy no-op MessageChannel implementation. - */ -export class MessageChannel { - port1 = { - port: new MessagePort(), - unref: () => this.port1.port, - }; - port2 = { - port: new MessagePort(), - unref: () => this.port2.port, - }; -}