From 455cf1743f70cb12025e36b3c4eb9a213fe77199 Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Mon, 29 Apr 2024 14:23:54 +0530 Subject: [PATCH] fix(ext/node): add support for MessagePort.removeListener/off (#23598) Closes https://github.com/denoland/deno/issues/23564 --- ext/node/polyfills/worker_threads.ts | 24 +++++++++++++++++++ ext/web/13_message_port.js | 5 ++++ .../specs/node/worker_threads/__test__.jsonc | 8 +++++++ .../message_port_removelistener.mjs | 9 +++++++ .../message_port_removelistener.mjs.out | 1 + 5 files changed, 47 insertions(+) create mode 100644 tests/specs/node/worker_threads/__test__.jsonc create mode 100644 tests/specs/node/worker_threads/message_port_removelistener.mjs create mode 100644 tests/specs/node/worker_threads/message_port_removelistener.mjs.out diff --git a/ext/node/polyfills/worker_threads.ts b/ext/node/polyfills/worker_threads.ts index 8f531368ae..e88e6368b5 100644 --- a/ext/node/polyfills/worker_threads.ts +++ b/ext/node/polyfills/worker_threads.ts @@ -473,6 +473,12 @@ class NodeMessageChannel { } } +const listeners = new SafeWeakMap< + // deno-lint-ignore no-explicit-any + (...args: any[]) => void, + // deno-lint-ignore no-explicit-any + (ev: any) => any +>(); function webMessagePortToNodeMessagePort(port: MessagePort) { port.on = port.addListener = function (this: MessagePort, name, listener) { // deno-lint-ignore no-explicit-any @@ -486,6 +492,24 @@ function webMessagePortToNodeMessagePort(port: MessagePort) { } else { throw new Error(`Unknown event: "${name}"`); } + listeners.set(listener, _listener); + return this; + }; + port.off = port.removeListener = function ( + this: MessagePort, + name, + listener, + ) { + if (name == "message") { + port.removeEventListener("message", listeners.get(listener)!); + } else if (name == "messageerror") { + port.removeEventListener("messageerror", listeners.get(listener)!); + } else if (name == "close") { + port.removeEventListener("close", listeners.get(listener)!); + } else { + throw new Error(`Unknown event: "${name}"`); + } + listeners.delete(listener); return this; }; port[nodeWorkerThreadCloseCb] = () => { diff --git a/ext/web/13_message_port.js b/ext/web/13_message_port.js index 4e4184f2a3..93145e8f74 100644 --- a/ext/web/13_message_port.js +++ b/ext/web/13_message_port.js @@ -190,6 +190,11 @@ class MessagePort extends EventTarget { this[_enabled] = true; while (true) { if (this[_id] === null) break; + // Exit if no message event listeners are present in Node compat mode. + if ( + typeof this[nodeWorkerThreadCloseCb] == "function" && + messageEventListenerCount === 0 + ) break; let data; try { data = await op_message_port_recv_message( diff --git a/tests/specs/node/worker_threads/__test__.jsonc b/tests/specs/node/worker_threads/__test__.jsonc new file mode 100644 index 0000000000..adcb9a85d6 --- /dev/null +++ b/tests/specs/node/worker_threads/__test__.jsonc @@ -0,0 +1,8 @@ +{ + "steps": [{ + "args": "run message_port_removelistener.mjs", + "output": "message_port_removelistener.mjs.out", + // Note: successful exit asserts that the test passed + "exitCode": 0 + }] +} diff --git a/tests/specs/node/worker_threads/message_port_removelistener.mjs b/tests/specs/node/worker_threads/message_port_removelistener.mjs new file mode 100644 index 0000000000..e0cac6ce93 --- /dev/null +++ b/tests/specs/node/worker_threads/message_port_removelistener.mjs @@ -0,0 +1,9 @@ +import { MessageChannel } from "node:worker_threads"; + +const { port1, port2 } = new MessageChannel(); +const listener = (message) => { + console.log(message); + port1.off("message", listener); +}; +port1.on("message", listener); +port2.postMessage("Hello World!"); diff --git a/tests/specs/node/worker_threads/message_port_removelistener.mjs.out b/tests/specs/node/worker_threads/message_port_removelistener.mjs.out new file mode 100644 index 0000000000..980a0d5f19 --- /dev/null +++ b/tests/specs/node/worker_threads/message_port_removelistener.mjs.out @@ -0,0 +1 @@ +Hello World!