UNPKG

multithreading

Version:

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

97 lines (96 loc) 3.44 kB
// @ts-nocheck This is a polyfill file import { isMainThread, parentPort, Worker as NodeWorker, } from "node:worker_threads"; globalThis.self = globalThis; // Polyfill ErrorEvent globally as it is used in both contexts globalThis.ErrorEvent = class ErrorEvent extends Event { constructor(type, init) { super(type, init); this.message = init?.message || ""; this.filename = init?.filename || ""; this.lineno = init?.lineno || 0; this.colno = init?.colno || 0; this.error = init?.error || null; } }; /** * Main Thread Implementation */ if (isMainThread) { // Directly overwrite global Worker globalThis.Worker = class Worker extends EventTarget { constructor(scriptURL, options) { super(); this.onmessage = null; this.onerror = null; const urlStr = scriptURL.toString(); const finalPath = urlStr.startsWith("file://") ? new URL(urlStr) : urlStr; this._worker = new NodeWorker(finalPath, { ...options }); this._worker.on("message", (data) => { const event = new MessageEvent("message", { data }); this.dispatchEvent(event); if (this.onmessage) this.onmessage(event); }); this._worker.on("error", (error) => { const event = new ErrorEvent("error", { error, message: error.message, }); this.dispatchEvent(event); if (this.onerror) this.onerror(event); }); this._worker.on("exit", (code) => { if (code !== 0) { const err = new Error(`Worker stopped with exit code ${code}`); const event = new ErrorEvent("error", { error: err, message: err.message, }); this.dispatchEvent(event); if (this.onerror) this.onerror(event); } }); } postMessage(message, transfer) { this._worker.postMessage(message, transfer); } terminate() { this._worker.terminate(); } }; } /** * Worker Thread Implementation */ if (!isMainThread && parentPort) { // We use Symbol.hasInstance so that "self instanceof WorkerGlobalScope" returns true // even though we can't easily change the prototype of the global Node object. class WorkerGlobalScope extends EventTarget { static [Symbol.hasInstance](instance) { return instance === globalThis; } } globalThis.WorkerGlobalScope = WorkerGlobalScope; // Polyfill postMessage globalThis.postMessage = (message, transfer) => { parentPort.postMessage(message, transfer); }; // Polyfill onmessage let currentHandler = globalThis.onmessage; parentPort.on("message", (data) => { const event = new MessageEvent("message", { data }); if (typeof globalThis.onmessage === "function") { globalThis.onmessage(event); } }); Object.defineProperty(globalThis, "onmessage", { get: () => currentHandler, set: (fn) => { currentHandler = fn; }, configurable: true, enumerable: true, }); }