UNPKG

multithreading

Version:

The missing standard library for multithreading in JavaScript (Works in the browser, Node.js, Deno, Bun).

73 lines (72 loc) 2.88 kB
import { deserialize, serialize, } from "./shared.js"; import "./sync/mod.js"; import "./json_buffer.js"; // Registry persists for the lifetime of the Worker const functionRegistry = new Map(); self.onmessage = async (event) => { const [type, taskId, fnId, rawArgs, code] = event.data; if (type === 0 /* WorkerTaskType.RUN */) { // We need a stable array to hold successfully hydrated handles. // We cannot use .map() because if it throws halfway, we lose the // references to the handles that succeeded const activeArgs = new Array(rawArgs.length); try { // As soon as 'deserialize' returns, we have a live Reference Count that must be disposed. for (let i = 0; i < rawArgs.length; i++) { activeArgs[i] = deserialize(rawArgs[i]); } let fn = functionRegistry.get(fnId); if (!fn) { // Cache miss: 'code' must be provided by the main thread logic if (!code) { throw new Error(`Function ID ${fnId} not found in worker registry and no code provided.`); } const base64Code = btoa(code); const dataUrl = `data:text/javascript;base64,${base64Code}`; const mod = await import(dataUrl); fn = mod.default; functionRegistry.set(fnId, fn); } let result = fn(...activeArgs); if (result instanceof Promise) result = await result; const [serializedResult, transferList] = serialize(result); self.postMessage([ 0 /* WorkerResponseType.RESULT */, taskId, serializedResult, ], { transfer: transferList }); } catch (err) { console.error(err); // Only log code if it was sent, otherwise we know it's a registry issue if (code) { console.log("[START WORKER CODE DUMP]"); console.log(code); console.log("[END WORKER CODE DUMP]"); } const error = err instanceof Error ? err : new Error(String(err)); self.postMessage([ 1 /* WorkerResponseType.ERROR */, taskId, error.message, error.stack, ]); } finally { for (const arg of activeArgs) { if (typeof arg === "object" && arg !== null && Symbol.dispose in arg) { try { arg[Symbol.dispose](); } catch (e) { console.error("Failed to dispose resource:", e); } } } } } }; self.onerror = (e) => { console.error(e.message, e); };