Heap.js
heap-js is an efficient JavaScript/TypeScript library providing a binary heap data structure, often used as a priority queue. It offers interfaces familiar to developers accustomed to Python's `heapq` module and Java's `PriorityQueue`, making it versatile for various algorithm implementations. The library is actively maintained, with the current stable version being 2.7.1, and receives frequent minor updates focusing on performance enhancements and new features like the `HeapAsync` class for asynchronous operations and comparators. Key differentiators include its robust performance, comprehensive testing, and support for both synchronous and asynchronous heap management, allowing it to handle complex prioritization logic. Instances default to an integer min-heap, with full customization options available for element comparison, aiming to be significantly faster than array sorting for common push/pop/peek operations in many scenarios.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'Heap') OR TypeError: Heap is not a constructor
cause Attempting to use `require('heap-js')` in a CommonJS module with a package primarily designed for ES Modules, or incorrect destructuring.fixFor ES Modules in Node.js or browser, use `import { Heap } from 'heap-js';`. If stuck with CommonJS, consider using dynamic import `import('heap-js').then(module => new module.Heap())` or ensure your build system correctly transpiles ESM imports. -
Expected top(N) to return sorted elements, but they are out of order.
cause Misunderstanding the behavior of `heap.top(N)` method after version 2.0.0, which explicitly states the output is not fully sorted.fixIf a fully sorted list of the top N elements is required, explicitly sort the result: `const topSorted = heap.top(N).sort(heap.comparator);`. -
My for...of loop on the heap emptied it out unexpectedly.
cause Direct iteration over a `Heap` instance (e.g., `for (const item of myHeap)`) consumes the heap by repeatedly calling `pop()`.fixIf you need to iterate without modifying the heap, first convert it to an array: `for (const item of myHeap.toArray()) { ... }`. Only use direct iteration if you intend to empty the heap.
Warnings
- breaking The `top(N)` method no longer guarantees a sorted output for the N elements. Only the first element (index 0) is guaranteed to be the top priority element. The remaining N-1 elements are only partially ordered.
- gotcha The `.iterator()` method, similar to Java's `PriorityQueue` implementation, does not guarantee to traverse elements in any particular order. The order of elements returned by the iterator is arbitrary.
- gotcha Directly using a heap instance as an iterator (e.g., in a `for...of` loop) will consume (empty) the heap, similar to Python's `heapq` behavior. This is because each iteration will `pop` an element.
- gotcha When defining custom comparators, ensure they return a number: `a - b` for min-heap (ascending order), or `b - a` for max-heap (descending order). Incorrect comparator logic can lead to an invalid heap state.
Install
-
npm install heap-js -
yarn add heap-js -
pnpm add heap-js
Imports
- Heap
const Heap = require('heap-js'); // Incorrect for modern CJS setups, use dynamic import or 'import type'import { Heap } from 'heap-js'; - HeapAsync
const HeapAsync = require('heap-js').HeapAsync;import { HeapAsync } from 'heap-js'; - Comparator
import { Comparator } from 'heap-js';import type { Comparator } from 'heap-js';
Quickstart
import { Heap, HeapAsync } from 'heap-js';
// 1. Basic synchronous min-heap for numbers
const minHeap = new Heap<number>();
minHeap.push(5);
minHeap.push(3);
minHeap.push(8);
console.log('Min-Heap peek:', minHeap.peek()); // Expected: 3
console.log('Min-Heap pop:', minHeap.pop()); // Expected: 3
console.log('Min-Heap elements:', minHeap.toArray()); // Expected: [5, 8]
// 2. Custom synchronous max-heap for objects
interface Task {
priority: number;
name: string;
}
// The comparator function defines the order: (a, b) => a - b for min-heap, b - a for max-heap
const maxHeap = new Heap<Task>((a, b) => b.priority - a.priority); // Max-heap comparator
maxHeap.push({ priority: 10, name: 'High Priority' });
maxHeap.push({ priority: 5, name: 'Medium Priority' });
maxHeap.push({ priority: 15, name: 'Critical Task' });
console.log('Max-Heap peek:', maxHeap.peek()?.name); // Expected: Critical Task
// 3. Example with HeapAsync for asynchronous comparisons or operations
// Requires an async comparator and awaits for heap methods
const asyncHeap = new HeapAsync<string>(async (a, b) => {
await new Promise(resolve => setTimeout(resolve, 10)); // Simulate async work
return a.length - b.length; // Sort by string length (min-heap)
});
async function runAsyncHeap() {
await asyncHeap.push('apple');
await asyncHeap.push('banana');
await asyncHeap.push('kiwi');
console.log('Async Heap peek:', await asyncHeap.peek()); // Expected: kiwi
console.log('Async Heap size:', asyncHeap.size());
}
runAsyncHeap();