From 052a089751faf2875a8bdb8067a9db2b881f8b0c Mon Sep 17 00:00:00 2001 From: Cheng Shao <terrorjack@type.dance> Date: Sun, 10 Nov 2024 18:12:09 +0000 Subject: [PATCH] wasm: fix setImmediate() implementation for Cloudflare Workers This patch fixes setImmediate() implementation for Cloudflare Workers in the wasm backend's js prelude script. Cloudflare Workers doesn't support the MessageChannel API, and we use a setTimeout() based fallback implementation in this case. (cherry picked from commit c37b96fa267cc0419172ee5da6d969def5a8135b) (cherry picked from commit 6bd2d9ad7e5e3f444cba1fba062df50708848893) --- utils/jsffi/prelude.mjs | 51 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/utils/jsffi/prelude.mjs b/utils/jsffi/prelude.mjs index b32a843ce27..fb27f612992 100644 --- a/utils/jsffi/prelude.mjs +++ b/utils/jsffi/prelude.mjs @@ -51,6 +51,10 @@ export class JSValManager { // The actual setImmediate() to be used. This is a ESM module top // level binding and doesn't pollute the globalThis namespace. +// +// To benchmark different setImmediate() implementations in the +// browser, use https://github.com/jphpsf/setImmediate-shim-demo as a +// starting point. const setImmediate = await (async () => { // node, bun, or other scripts might have set this up in the browser if (globalThis.setImmediate) { @@ -67,30 +71,35 @@ const setImmediate = await (async () => { return (cb, ...args) => scheduler.postTask(() => cb(...args)); } - // A simple & fast setImmediate() implementation for browsers. It's - // not a drop-in replacement for node.js setImmediate() because: - // 1. There's no clearImmediate(), and setImmediate() doesn't return - // anything - // 2. There's no guarantee that callbacks scheduled by setImmediate() - // are executed in the same order (in fact it's the opposite lol), - // but you are never supposed to rely on this assumption anyway - class SetImmediate { - #fs = []; - #mc = new MessageChannel(); + // Cloudflare workers doesn't support MessageChannel + if (globalThis.MessageChannel) { + // A simple & fast setImmediate() implementation for browsers. It's + // not a drop-in replacement for node.js setImmediate() because: + // 1. There's no clearImmediate(), and setImmediate() doesn't return + // anything + // 2. There's no guarantee that callbacks scheduled by setImmediate() + // are executed in the same order (in fact it's the opposite lol), + // but you are never supposed to rely on this assumption anyway + class SetImmediate { + #fs = []; + #mc = new MessageChannel(); - constructor() { - this.#mc.port1.addEventListener("message", () => { - this.#fs.pop()(); - }); - this.#mc.port1.start(); - } + constructor() { + this.#mc.port1.addEventListener("message", () => { + this.#fs.pop()(); + }); + this.#mc.port1.start(); + } - setImmediate(cb, ...args) { - this.#fs.push(() => cb(...args)); - this.#mc.port2.postMessage(undefined); + setImmediate(cb, ...args) { + this.#fs.push(() => cb(...args)); + this.#mc.port2.postMessage(undefined); + } } + + const sm = new SetImmediate(); + return (cb, ...args) => sm.setImmediate(cb, ...args); } - const sm = new SetImmediate(); - return (cb, ...args) => sm.setImmediate(cb, ...args); + return (cb, ...args) => setTimeout(cb, 0, ...args); })(); -- GitLab