worker
The worker utility simplifies the use of Web Workers by allowing you to run heavy computations in a background thread without creating separate files. It supports importing external dependencies and handles all the complex message-passing logic for you.
Implementation
View Source Code
ts
/**
* Creates a function that runs the provided callback in a web worker with specified dependencies.
*
* @example
* const sum = worker(({ _ }) => (...args) => _.sum([...args]), ['https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js']);
* await sum(1, 2); // 3
*
* @param callback - A function that receives the worker's `self` and performs work.
* @param dependencies - (optional) array of URLs to scripts that the worker should import.
*
* @returns A function that takes the arguments for the callback and returns a promise with the result.
*/
// biome-ignore lint/suspicious/noExplicitAny: -
export function worker<T extends (...args: any) => any, R = Awaited<ReturnType<T>>>(
// biome-ignore lint/suspicious/noExplicitAny: -
callback: (self: any) => T,
dependencies: string[] = [],
): (...args: Parameters<T>) => Promise<R> {
const callbackString = callback.toString();
const workerScript = `
${dependencies.map((dep) => `importScripts('${dep}');`).join('\n')}
const callback = (${callbackString})(self);
self.onmessage = async function(e) {
try {
const result = await callback(...e.data.args);
self.postMessage({ success: true, result });
} catch (error) {
self.postMessage({ success: false, error: error?.message || String(error) });
}
};
`;
const blob = new Blob([workerScript], { type: 'application/javascript' });
const workerUrl = URL.createObjectURL(blob);
return (...args: Parameters<T>): Promise<R> =>
new Promise((resolve, reject) => {
const workerInstance = new Worker(workerUrl);
const cleanup = () => {
workerInstance.terminate();
URL.revokeObjectURL(workerUrl);
};
workerInstance.onmessage = (e) => {
cleanup();
if (e.data.success) {
resolve(e.data.result);
} else {
reject(new Error(e.data.error));
}
};
workerInstance.onerror = (err) => {
cleanup();
reject(new Error(err.message || 'Worker error occurred'));
};
workerInstance.postMessage({ args });
});
}Features
- Browser Only: Leverages the native Web Worker API.
- Background Execution: Offloads CPU-intensive tasks to prevent UI freezing.
- Integrated Dependencies: Import external scripts directly into the worker environment.
- Promise-based: Call background functions as if they were local async functions.
API
ts
function worker<T extends (...args: any[]) => any>(
callback: (context: any) => T,
dependencies?: string[],
): (...args: any[]) => Promise<any>;Parameters
callback: A factory function that runs inside the worker. It receives a context (includingself) and must return the function that will perform the work.dependencies: Optional. An array of URLs for external scripts to be imported into the worker usingimportScripts.
Returns
- A new function that, when called, executes the logic in a Web Worker and returns a Promise with the result.
Examples
Heavy Data Processing
ts
import { worker } from '@vielzeug/toolkit';
// This function will run in a separate thread
const processLargeDataset = worker(() => {
return (data: number[]) => {
// Perform complex calculations...
return data.map((n) => Math.sqrt(n) * Math.PI).reduce((a, b) => a + b);
};
});
const result = await processLargeDataset([1, 2, 3, 4, 5, 6]);Using External Libraries
ts
import { worker } from '@vielzeug/toolkit';
const calculateHash = worker(() => {
return (text: string) => {
// Logic goes here
return text;
};
});
const hash = await calculateHash('Hello World');Implementation Notes
- Creates a
Blobfrom the stringified function to instantiate the Worker. - Automatically terminates the internal worker instance after the task is complete (depending on implementation details, usually stays alive for reuse if optimized).
- Throws an error if used in an environment without
Workersupport (e.g., standard Node.js).