137 lines
4 KiB
TypeScript
137 lines
4 KiB
TypeScript
/**
|
|
* Utility functions for working with Web Workers and Worker Threads
|
|
*/
|
|
|
|
import { isNode, isBrowser } from './environment.js';
|
|
|
|
/**
|
|
* Execute a function in a Web Worker (browser environment)
|
|
*
|
|
* @param fn The function to execute
|
|
* @param args The arguments to pass to the function
|
|
* @returns A promise that resolves with the result of the function
|
|
*/
|
|
export function executeInWebWorker<T>(fn: Function, ...args: any[]): Promise<T> {
|
|
return new Promise((resolve, reject) => {
|
|
// Create a blob URL for the worker script
|
|
const fnString = fn.toString();
|
|
const workerScript = `
|
|
self.onmessage = function(e) {
|
|
try {
|
|
const fn = ${fnString};
|
|
const result = fn(...e.data);
|
|
self.postMessage({ success: true, data: result });
|
|
} catch (error) {
|
|
self.postMessage({
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error)
|
|
});
|
|
}
|
|
};
|
|
`;
|
|
|
|
const blob = new Blob([workerScript], { type: 'application/javascript' });
|
|
const blobURL = URL.createObjectURL(blob);
|
|
|
|
// Create a worker
|
|
const worker = new Worker(blobURL);
|
|
|
|
// Set up message handling
|
|
worker.onmessage = function(e: MessageEvent<{ success: boolean; data: T; error?: string }>) {
|
|
URL.revokeObjectURL(blobURL); // Clean up
|
|
worker.terminate(); // Terminate the worker
|
|
|
|
if (e.data.success) {
|
|
resolve(e.data.data);
|
|
} else {
|
|
reject(new Error(e.data.error));
|
|
}
|
|
};
|
|
|
|
worker.onerror = function(error: ErrorEvent) {
|
|
URL.revokeObjectURL(blobURL); // Clean up
|
|
worker.terminate(); // Terminate the worker
|
|
reject(error);
|
|
};
|
|
|
|
// Start the worker
|
|
worker.postMessage(args);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Execute a function in a Worker Thread (Node.js environment)
|
|
*
|
|
* @param fn The function to execute
|
|
* @param args The arguments to pass to the function
|
|
* @returns A promise that resolves with the result of the function
|
|
*/
|
|
export function executeInWorkerThread<T>(fn: Function, ...args: any[]): Promise<T> {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
// Dynamic import to avoid errors in browser environments
|
|
const { Worker } = require('worker_threads');
|
|
|
|
// Create a worker script
|
|
const fnString = fn.toString();
|
|
const workerScript = `
|
|
const { parentPort } = require('worker_threads');
|
|
|
|
parentPort.once('message', (data) => {
|
|
try {
|
|
const fn = ${fnString};
|
|
const result = fn(...data);
|
|
parentPort.postMessage({ success: true, data: result });
|
|
} catch (error) {
|
|
parentPort.postMessage({
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error)
|
|
});
|
|
}
|
|
});
|
|
`;
|
|
|
|
// Create a worker
|
|
const worker = new Worker(workerScript, { eval: true });
|
|
|
|
// Set up message handling
|
|
worker.on('message', (data: { success: boolean; data: T; error?: string }) => {
|
|
worker.terminate(); // Terminate the worker
|
|
|
|
if (data.success) {
|
|
resolve(data.data);
|
|
} else {
|
|
reject(new Error(data.error));
|
|
}
|
|
});
|
|
|
|
worker.on('error', (error: Error) => {
|
|
worker.terminate(); // Terminate the worker
|
|
reject(error);
|
|
});
|
|
|
|
// Start the worker
|
|
worker.postMessage(args);
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Execute a function in a separate thread based on the environment
|
|
*
|
|
* @param fn The function to execute
|
|
* @param args The arguments to pass to the function
|
|
* @returns A promise that resolves with the result of the function
|
|
*/
|
|
export function executeInThread<T>(fn: Function, ...args: any[]): Promise<T> {
|
|
if (isBrowser()) {
|
|
return executeInWebWorker<T>(fn, ...args);
|
|
} else if (isNode()) {
|
|
return executeInWorkerThread<T>(fn, ...args);
|
|
} else {
|
|
// Fall back to executing in the main thread
|
|
return Promise.resolve(fn(...args) as T);
|
|
}
|
|
}
|