Utility data structures used internally by the pool, also available for external use including double-ended queues and priority queues for advanced resource management scenarios.
A double-ended queue implementation backed by a doubly-linked list, supporting efficient insertion and removal from both ends.
/**
* Double-ended queue with efficient operations at both ends
*/
class Deque {
constructor();
/** Removes and returns the first element */
shift(): any;
/** Adds element to the beginning */
unshift(element: any): void;
/** Adds element to the end */
push(element: any): void;
/** Removes and returns the last element */
pop(): any;
/** Returns iterator for forward traversal */
iterator(): DequeIterator;
/** Returns iterator for reverse traversal */
reverseIterator(): DequeIterator;
/** ES6 iterator support */
[Symbol.iterator](): DequeIterator;
/** Reference to first element without removing */
readonly head: any;
/** Reference to last element without removing */
readonly tail: any;
/** Number of elements in the deque */
readonly length: number;
}Usage Examples:
const { Deque } = require('generic-pool');
// Create and use deque
const queue = new Deque();
// Add elements
queue.push('first');
queue.push('second');
queue.unshift('before-first');
console.log(queue.length); // 3
console.log(queue.head); // 'before-first'
console.log(queue.tail); // 'second'
// Remove elements
const first = queue.shift(); // 'before-first'
const last = queue.pop(); // 'second'
// Iteration
queue.push('a', 'b', 'c');
for (const item of queue) {
console.log(item); // 'a', 'b', 'c'
}
// Manual iteration
const iterator = queue.iterator();
let current = iterator.next();
while (!current.done) {
console.log(current.value);
current = iterator.next();
}
// Reverse iteration
const reverseIter = queue.reverseIterator();
let reverseCurrent = reverseIter.next();
while (!reverseCurrent.done) {
console.log(reverseCurrent.value);
reverseCurrent = reverseIter.next();
}A priority queue implementation that manages multiple priority levels, with higher priority items dequeued first.
/**
* Priority queue with configurable priority levels
*/
class PriorityQueue {
/**
* Creates a priority queue
* @param size - Number of priority levels (higher number = more levels)
*/
constructor(size: number);
/**
* Adds an item with specified priority
* @param obj - Item to add
* @param priority - Priority level (0 = highest priority)
*/
enqueue(obj: any, priority: number): void;
/** Removes and returns the highest priority item */
dequeue(): any;
/** Total number of items across all priority levels */
readonly length: number;
/** Reference to highest priority item without removing */
readonly head: any;
/** Reference to lowest priority item without removing */
readonly tail: any;
}Usage Examples:
const { PriorityQueue } = require('generic-pool');
// Create priority queue with 3 levels (0=high, 1=medium, 2=low)
const pqueue = new PriorityQueue(3);
// Add items with different priorities
pqueue.enqueue('low-priority-task', 2);
pqueue.enqueue('high-priority-task', 0);
pqueue.enqueue('medium-priority-task', 1);
pqueue.enqueue('another-high-priority', 0);
console.log(pqueue.length); // 4
// Dequeue items (highest priority first)
console.log(pqueue.dequeue()); // 'high-priority-task'
console.log(pqueue.dequeue()); // 'another-high-priority'
console.log(pqueue.dequeue()); // 'medium-priority-task'
console.log(pqueue.dequeue()); // 'low-priority-task'
// Priority boundaries
const workQueue = new PriorityQueue(5);
// Out-of-range priorities get clamped
workQueue.enqueue('task1', -1); // Becomes priority 0 (highest)
workQueue.enqueue('task2', 10); // Becomes priority 4 (lowest)
workQueue.enqueue('task3', 2); // Stays priority 2
// Task scheduling example
class TaskScheduler {
constructor() {
this.queue = new PriorityQueue(3);
this.processing = false;
}
addTask(task, priority = 2) {
this.queue.enqueue(task, priority);
this.processNext();
}
async processNext() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
const task = this.queue.dequeue();
try {
await task.execute();
} catch (error) {
console.error('Task failed:', error);
}
this.processing = false;
// Process next task if available
if (this.queue.length > 0) {
setImmediate(() => this.processNext());
}
}
}Default resource eviction strategy for determining when idle resources should be removed from the pool.
/**
* Default eviction strategy for pool resources
*/
class DefaultEvictor {
/**
* Determines if a resource should be evicted
* @param config - Pool configuration object
* @param pooledResource - Resource wrapper with timing information
* @param availableObjectsCount - Current number of available resources
* @returns true if resource should be evicted, false otherwise
*/
evict(config: any, pooledResource: any, availableObjectsCount: number): boolean;
}Usage Examples:
const { DefaultEvictor } = require('generic-pool');
// Custom pool with custom evictor
class CustomEvictor {
evict(config, pooledResource, availableObjectsCount) {
const idleTime = Date.now() - pooledResource.lastIdleTime;
// Custom eviction logic
if (idleTime > 60000 && availableObjectsCount > config.min) {
return true; // Evict resources idle for more than 1 minute
}
return false;
}
}
// Use custom evictor with pool
const { Pool, Deque, PriorityQueue } = require('generic-pool');
const customPool = new Pool(
CustomEvictor,
Deque,
PriorityQueue,
factory,
options
);
// Eviction monitoring
class EvictionMonitor extends DefaultEvictor {
constructor() {
super();
this.evictionCount = 0;
this.evictionHistory = [];
}
evict(config, pooledResource, availableObjectsCount) {
const shouldEvict = super.evict(config, pooledResource, availableObjectsCount);
if (shouldEvict) {
this.evictionCount++;
this.evictionHistory.push({
timestamp: Date.now(),
idleTime: Date.now() - pooledResource.lastIdleTime,
availableCount: availableObjectsCount
});
// Keep only last 100 evictions
if (this.evictionHistory.length > 100) {
this.evictionHistory.shift();
}
console.log(`Resource evicted (total: ${this.evictionCount})`);
}
return shouldEvict;
}
getStats() {
return {
totalEvictions: this.evictionCount,
recentEvictions: this.evictionHistory.length,
averageIdleTime: this.evictionHistory.reduce((sum, e) => sum + e.idleTime, 0) / this.evictionHistory.length
};
}
}Both Deque and the internal data structures provide comprehensive iterator support for traversal.
Usage Examples:
const { Deque } = require('generic-pool');
const queue = new Deque();
queue.push('a', 'b', 'c', 'd');
// ES6 for...of iteration
for (const item of queue) {
console.log(item); // 'a', 'b', 'c', 'd'
}
// Array spread operator
const items = [...queue]; // ['a', 'b', 'c', 'd']
// Manual iterator usage
const iterator = queue.iterator();
let result = iterator.next();
while (!result.done) {
console.log(result.value);
result = iterator.next();
}
// Reverse iteration
const reverseIterator = queue.reverseIterator();
const reverseItems = [];
let reverseResult = reverseIterator.next();
while (!reverseResult.done) {
reverseItems.push(reverseResult.value);
reverseResult = reverseIterator.next();
}
console.log(reverseItems); // ['d', 'c', 'b', 'a']
// Iterator with external state
function processQueueWithState(queue) {
const iterator = queue.iterator();
let index = 0;
return {
next() {
const result = iterator.next();
if (!result.done) {
return {
index: index++,
value: result.value,
done: false
};
}
return { done: true };
}
};
}
const processor = processQueueWithState(queue);
let processed = processor.next();
while (!processed.done) {
console.log(`Item ${processed.index}: ${processed.value}`);
processed = processor.next();
}Using the data structures outside of the pool context for custom applications.
Usage Examples:
const { Deque, PriorityQueue } = require('generic-pool');
// Custom buffer implementation
class CircularBuffer {
constructor(maxSize) {
this.buffer = new Deque();
this.maxSize = maxSize;
}
add(item) {
if (this.buffer.length >= this.maxSize) {
this.buffer.shift(); // Remove oldest
}
this.buffer.push(item);
}
getAll() {
return [...this.buffer];
}
getLatest(count) {
const items = [];
const iterator = this.buffer.reverseIterator();
let result = iterator.next();
while (!result.done && items.length < count) {
items.push(result.value);
result = iterator.next();
}
return items;
}
}
// Request queue with priority handling
class RequestQueue {
constructor() {
this.queue = new PriorityQueue(3); // High, medium, low
this.processing = false;
}
addRequest(request, priority = 2) {
this.queue.enqueue({
id: Math.random().toString(36),
request,
timestamp: Date.now(),
priority
}, priority);
this.processQueue();
}
async processQueue() {
if (this.processing) return;
this.processing = true;
while (this.queue.length > 0) {
const item = this.queue.dequeue();
console.log(`Processing request ${item.id} (priority ${item.priority})`);
try {
await this.handleRequest(item.request);
} catch (error) {
console.error(`Request ${item.id} failed:`, error);
}
}
this.processing = false;
}
async handleRequest(request) {
// Simulate request processing
await new Promise(resolve => setTimeout(resolve, 100));
}
getQueueStatus() {
return {
pending: this.queue.length,
processing: this.processing,
nextPriority: this.queue.head ? this.queue.head.priority : null
};
}
}