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
JavaScript
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);
};