Offload tasks to a pool of workers on node.js and in the browser
Overall
score
95%
Enhanced Promise implementation with cancellation and timeout support, plus utilities for efficiently transferring objects between workers. These utilities provide additional control over asynchronous operations and performance optimization for worker communication.
Custom Promise implementation that extends standard Promise functionality with cancellation, timeout, and additional utility methods.
/**
* Create a new Promise with enhanced capabilities
* @param {function} handler - Promise executor function (resolve, reject) => void
* @param {Promise} [parent] - Parent promise for cancellation propagation
*/
class Promise {
constructor(handler, parent)
/** Standard promise then method with enhanced chaining */
then(onSuccess, onFail) -> Promise
/** Standard promise catch method */
catch(onFail) -> Promise
/** Cancel the promise (rejects with CancellationError) */
cancel() -> Promise
/** Set timeout for promise (rejects with TimeoutError) */
timeout(delay) -> Promise
/** Execute callback on resolve or reject */
always(fn) -> Promise
/** Standard finally method */
finally(fn) -> Promise
/** Promise status properties (readonly) */
resolved: boolean
rejected: boolean
pending: boolean
}Usage Examples:
const workerpool = require('workerpool');
const pool = workerpool.pool();
// Basic promise usage (same as standard Promise)
const result = await pool.exec('longTask', [data])
.then(result => processResult(result))
.catch(error => handleError(error));
// Promise cancellation
const taskPromise = pool.exec('longRunningTask', [data]);
// Cancel after 5 seconds
setTimeout(() => {
taskPromise.cancel();
}, 5000);
try {
const result = await taskPromise;
} catch (error) {
if (error instanceof workerpool.Promise.CancellationError) {
console.log('Task was cancelled');
}
}
// Promise timeout
const result = await pool.exec('taskThatMightHang', [data])
.timeout(10000) // 10 second timeout
.catch(error => {
if (error instanceof workerpool.Promise.TimeoutError) {
console.log('Task timed out');
}
throw error;
});
// Always execute cleanup regardless of outcome
await pool.exec('taskWithResources', [data])
.always(() => {
console.log('Cleaning up resources...');
cleanup();
});Static utility methods for working with multiple promises.
/**
* Wait for all promises to resolve
* @param {Promise[]} promises - Array of promises
* @returns {Promise<any[]>} Promise resolving to array of results
*/
Promise.all(promises) -> Promise<any[]>
/**
* Create a deferred promise with external resolve/reject
* @returns {object} Object with promise, resolve, and reject properties
*/
Promise.defer() -> { promise: Promise, resolve: function, reject: function }Usage Examples:
// Execute multiple tasks in parallel
const tasks = [
pool.exec('task1', [data1]),
pool.exec('task2', [data2]),
pool.exec('task3', [data3])
];
const results = await workerpool.Promise.all(tasks);
console.log('All tasks completed:', results);
// Deferred promise for complex control flow
const deferred = workerpool.Promise.defer();
// Set up async operation with external control
setTimeout(() => {
if (someCondition) {
deferred.resolve('Success!');
} else {
deferred.reject(new Error('Failed'));
}
}, 1000);
const result = await deferred.promise;Special error types for promise cancellation and timeout scenarios.
/**
* Error thrown when promise is cancelled
*/
class CancellationError extends Error {
constructor(message = 'promise cancelled')
}
/**
* Error thrown when promise times out
*/
class TimeoutError extends Error {
constructor(message = 'timeout exceeded')
}
// Access via Promise class
Promise.CancellationError = CancellationError
Promise.TimeoutError = TimeoutErrorUsage Examples:
try {
const result = await pool.exec('longTask', [data])
.timeout(5000);
} catch (error) {
if (error instanceof workerpool.Promise.CancellationError) {
console.log('Task was cancelled by user');
} else if (error instanceof workerpool.Promise.TimeoutError) {
console.log('Task timed out after 5 seconds');
} else {
console.log('Task failed with error:', error.message);
}
}
// Handle different error types with specific logic
pool.exec('criticalTask', [data])
.timeout(30000)
.catch(error => {
if (error instanceof workerpool.Promise.TimeoutError) {
// Retry with longer timeout
return pool.exec('criticalTask', [data]).timeout(60000);
}
throw error; // Re-throw other errors
});Wrapper class for transferable objects that can be efficiently moved between workers without copying data. Only supported in Web Workers and worker_threads environments.
/**
* Wrap objects for efficient transfer between workers
* @param {any} message - The data to transfer
* @param {object[]} transfer - Array of transferable objects
*/
class Transfer {
constructor(message, transfer)
message: any // The transferred data
transfer: object[] // Array of transferable objects
}Usage Examples:
// In main thread - transfer ArrayBuffer to worker
const buffer = new ArrayBuffer(1024 * 1024); // 1MB buffer
const uint8Array = new Uint8Array(buffer);
// Fill with data
for (let i = 0; i < uint8Array.length; i++) {
uint8Array[i] = i % 256;
}
// Transfer buffer to worker (zero-copy)
const result = await pool.exec('processBuffer', [buffer], {
transfer: [buffer] // Buffer ownership transferred to worker
});
// buffer is now detached and unusable in main thread
console.log(buffer.byteLength); // 0
// In worker script
const workerpool = require('workerpool');
workerpool.worker({
processBuffer: function(buffer) {
const uint8Array = new Uint8Array(buffer);
// Process the buffer
for (let i = 0; i < uint8Array.length; i++) {
uint8Array[i] = uint8Array[i] * 2;
}
// Return processed buffer back to main thread
return new workerpool.Transfer(buffer, [buffer]);
},
createAndTransferBuffer: function(size) {
// Create buffer in worker
const buffer = new ArrayBuffer(size);
const view = new Float32Array(buffer);
// Fill with computed data
for (let i = 0; i < view.length; i++) {
view[i] = Math.sin(i / 1000);
}
// Transfer back to main thread
return new workerpool.Transfer({
buffer: buffer,
length: view.length,
type: 'Float32Array'
}, [buffer]);
}
});// Transfer multiple objects
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(800, 600);
const buffer1 = new ArrayBuffer(1024);
const buffer2 = new ArrayBuffer(2048);
const result = await pool.exec('processMultipleBuffers', [
{
imageData: imageData,
buffer1: buffer1,
buffer2: buffer2
}
], {
transfer: [imageData.data.buffer, buffer1, buffer2]
});
// Worker handling multiple transfers
workerpool.worker({
processMultipleBuffers: function(data) {
// Process image data
const imageArray = new Uint8ClampedArray(data.imageData.data);
// ... process image
// Process buffers
const array1 = new Uint8Array(data.buffer1);
const array2 = new Uint8Array(data.buffer2);
// ... process arrays
// Create result with new transferable
const resultBuffer = new ArrayBuffer(4096);
const resultArray = new Float32Array(resultBuffer);
// Fill result
for (let i = 0; i < resultArray.length; i++) {
resultArray[i] = computeResult(i);
}
return new workerpool.Transfer({
success: true,
resultBuffer: resultBuffer
}, [resultBuffer]);
}
});Transfer objects are only supported in specific environments:
// Feature detection
const supportsTransfer = workerpool.platform === 'browser' ||
(workerpool.platform === 'node' && process.versions.node >= '10.5.0');
if (supportsTransfer) {
// Use transfer objects for performance
const result = await pool.exec('processLargeBuffer', [buffer], {
transfer: [buffer]
});
} else {
// Fall back to regular parameter passing (data copied)
const result = await pool.exec('processLargeBuffer', [buffer]);
}// Check if enhanced promises are available
const enhancedPromises = typeof workerpool.Promise !== 'undefined';
if (enhancedPromises) {
// Use cancellation and timeout features
const task = pool.exec('longTask', [data])
.timeout(10000)
.catch(error => {
if (error instanceof workerpool.Promise.TimeoutError) {
console.log('Task timed out');
}
});
} else {
// Fall back to standard promise handling
const task = pool.exec('longTask', [data]);
}Install with Tessl CLI
npx tessl i tessl/npm-workerpoolevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10