Asynchronous function queue with adjustable concurrency control and Promise/callback support
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive event system for monitoring job lifecycle, handling errors, and responding to timeouts. The Queue extends EventTarget and uses custom QueueEvent instances.
Custom event class that carries detailed information about queue operations.
/**
* Custom event class for queue events with detail payload
*/
class QueueEvent extends Event {
constructor(name: string, detail: any);
/** Event-specific data payload */
readonly detail: any;
}Standard EventTarget methods for managing event listeners.
/**
* Add event listener for queue events
* @param name - Event name to listen for
* @param callback - Event handler function
* @param options - Optional listener options
*/
addEventListener<Event extends keyof EventsMap>(
name: Event,
callback: EventListenerOrEventListenerObject<QueueEvent<Event, EventsMap[Event]>>,
options?: AddEventListenerOptions | boolean
): void;
/**
* Remove event listener
* @param name - Event name to stop listening for
* @param callback - Event handler function to remove
* @param options - Optional listener options
*/
removeEventListener<Event extends keyof EventsMap>(
name: Event,
callback: EventListenerOrEventListenerObject<QueueEvent<Event, EventsMap[Event]>>,
options?: EventListenerOptions | boolean
): void;
/**
* Dispatch custom queue events
* @param event - QueueEvent to dispatch
* @returns Whether the event was handled
*/
dispatchEvent<Event extends keyof EventsMap>(event: QueueEvent<Event, EventsMap[Event]>): boolean;
/**
* Event listener callback type
*/
type EventListenerOrEventListenerObject<Event extends QueueEvent<keyof EventsMap, EventsMap[keyof EventsMap]>> =
(event: Event) => void | { handleEvent(Event: Event): void; };Fired immediately before a job begins execution.
// Event detail structure
interface StartEventDetail {
job?: QueueWorker; // Optional in TypeScript definitions
}Usage Example:
q.addEventListener('start', (event) => {
if (event.detail.job) {
console.log('Job starting:', event.detail.job.name);
}
});Fired after a job successfully completes execution.
// Event detail structure
interface SuccessEventDetail {
result: any[]; // Job return values array
}Usage Example:
q.addEventListener('success', (event) => {
const { result } = event.detail;
console.log('Job completed successfully:', result);
});Fired when a job calls its callback with an error or throws an exception.
// Event detail structure
interface ErrorEventDetail {
error: Error; // The error that occurred
job: QueueWorker; // The job that failed
}Usage Example:
q.addEventListener('error', (event) => {
const { error, job } = event.detail;
console.error('Job failed:', job.name, error.message);
// Log error details
logger.error({
jobName: job.name,
error: error.message,
stack: error.stack
});
});Fired when a job exceeds its timeout duration without completing.
// Event detail structure
interface TimeoutEventDetail {
next: (error?: Error, ...result: any[]) => void; // Callback to continue
job: QueueWorker; // The job that timed out
}Usage Example:
q.addEventListener('timeout', (event) => {
const { next, job } = event.detail;
console.log('Job timed out:', job.toString().replace(/\n/g, ''));
// Cancel the job and continue processing
next(new Error('Job timed out'));
// Or allow job to continue (job might still complete)
// next();
});Fired when the queue finishes processing all jobs, either successfully or due to an error.
// Event detail structure
interface EndEventDetail {
error?: Error; // Error if queue ended due to failure
}Usage Example:
q.addEventListener('end', (event) => {
const { error } = event.detail;
if (error) {
console.error('Queue ended with error:', error.message);
} else {
console.log('Queue completed successfully');
}
// Cleanup resources
cleanup();
});import Queue from "queue";
const q = new Queue({
concurrency: 2,
timeout: 5000,
results: []
});
// Monitor job lifecycle
q.addEventListener('start', (event) => {
console.log(`Starting job: ${event.detail.job.name || 'anonymous'}`);
});
q.addEventListener('success', (event) => {
console.log(`Job completed: ${event.detail.result}`);
});
q.addEventListener('error', (event) => {
console.error(`Job failed: ${event.detail.error.message}`);
});
q.addEventListener('timeout', (event) => {
console.warn('Job timed out, cancelling...');
event.detail.next(new Error('Timeout'));
});
q.addEventListener('end', (event) => {
if (event.detail.error) {
console.error('Queue failed:', event.detail.error.message);
} else {
console.log('All jobs completed successfully');
console.log('Results:', q.results);
}
});
// Add some jobs
q.push(
function fastJob(callback) {
setTimeout(() => callback(null, 'fast'), 100);
},
function slowJob(callback) {
setTimeout(() => callback(null, 'slow'), 10000); // Will timeout
},
function errorJob(callback) {
callback(new Error('Something went wrong'));
}
);
// Start processing
q.start();/**
* Complete mapping of event names to their detail types
*/
interface EventsMap {
start: { job?: QueueWorker };
success: { result: any[] };
error: { error: Error, job: QueueWorker };
timeout: { next: (err?: Error, ...result: any[]) => void, job: QueueWorker };
end: { error?: Error };
}Install with Tessl CLI
npx tessl i tessl/npm-queue