UNPKG

async-multi-worker

Version:
87 lines (83 loc) 3.18 kB
'use strict'; var index = require('./node/index.cjs'); var universalWorker = require('./node/universal-worker.cjs'); /* eslint-disable @typescript-eslint/no-explicit-any */ /** * A generic handler for making asynchronous function calls to a Worker. * * This class manages communication between the main thread and a worker, allowing you to call worker-exposed functions as Promises. * It handles message passing, result/error propagation, timeouts, and worker cleanup. * * @template T - The type describing the functions exposed by the worker . * * @see func for calling worker functions * @see terminate for cleanup */ class DedicatedWorker { constructor(workerURL) { this.calls = new Map(); this.cleanup = (error) => { for (const { reject } of this.calls.values()) { reject(error ?? new Error("Worker was terminated")); } this.calls.clear(); }; /** * Returns a function that calls a method in the worker asynchronously with optional timeout. * * @template K - The key of the function in the worker object. * @param funcName - The name of the function to call in the worker. * @param timeoutMs - Optional timeout in milliseconds (default: 5000ms). * @returns A function that, when called with arguments, returns a Promise resolving to the result of the worker function. * * @example * const add = workerProxy.func('add'); * const result = await add(1, 2); */ this.func = (funcName) => { return (...args) => new Promise((resolve, reject) => { const id = index.getUUID(); this.calls.set(id, { resolve, reject }); this.worker.postMessage({ func: funcName, args, id }); }); }; /** * Terminates the worker and cleans up all pending calls. * This method removes all event listeners and clears the calls map. * It should be called when the worker is no longer needed to prevent memory leaks. */ this.terminate = () => { this.cleanup(); this.worker.terminate(); }; this.workerURL = workerURL; this.worker = this.spawnWorker(); this.worker.onmessage = (data) => { const { id, result, error } = data; const call = this.calls.get(id); if (!call) return; if (error) { const e = new Error(error.message); if (error.name) e.name = error.name; if (error.stack) e.stack = error.stack; call.reject(e); } else { call.resolve(result); } this.calls.delete(id); }; this.worker.onerror = this.cleanup; this.worker.onexit = () => this.cleanup(); } spawnWorker() { return new universalWorker.UniversalWorker(this.workerURL); } get busy() { return this.calls.size > 0; } } exports.DedicatedWorker = DedicatedWorker;