Performance and Benchmarks
Relevant source files
The following files were used as context for generating this wiki page:
htmlparser2 is designed as a fast and forgiving HTML/XML parser for Node.js and the web. Its primary performance goal is to provide a streaming, callback-based interface that minimizes memory allocations by processing documents incrementally. Unlike parsers that aim for strict HTML5 specification compliance, htmlparser2 takes strategic shortcuts to maximize throughput, making it the fastest HTML parser in the Node.js ecosystem for general-purpose use cases.
Sources: README.md:12-14, README.md:26-28
Benchmarking Results
The performance of htmlparser2 is validated using the htmlparser-benchmark suite, which tests parsers against real-world websites. In automated GitHub Actions benchmarks, htmlparser2 consistently outperforms other popular parsers in terms of milliseconds per file.
Comparative Performance Table
The following table lists the performance of various parsers based on real-world data (lower is better):
| Parser | Performance (ms/file) |
|---|---|
| htmlparser2 | 2.17215 ± 3.81587 |
| node-html-parser | 2.35983 ± 1.54487 |
| html5parser | 2.43468 ± 2.81501 |
| htmlparser2-dom | 3.09034 ± 4.77033 |
| parse5 | 9.70406 ± 6.74872 |
| saxes | 45.7921 ± 128.691 |
Sources: README.md:204-222
Architectural Performance Optimizations
Minimal Allocation Strategy
The parser uses a callback interface (the Handler interface) which allows it to process chunks of data without necessarily building a full Document Object Model (DOM) unless explicitly requested. This reduces garbage collection pressure and memory usage.
Sources: README.md:26-27, src/Parser.ts:250-272
Tokenization Speed
The Tokenizer class is implemented as a state machine that processes character code points directly. It uses several optimizations:
- Fast-forwarding: The
fastForwardTomethod allows the tokenizer to skip through the buffer until it finds specific characters (like<or&), avoiding expensive state transitions for every character in a text block. - Buffer Management: Instead of concatenating strings, the
Parsermaintains a list of buffers and uses indices to slice data only when an event is emitted.
Sources: src/Tokenizer.ts:397-414, src/Parser.ts:316-320, src/Parser.ts:639-659
Tokenizer Flow
This diagram illustrates how data flows through the tokenizer to maintain high performance by skipping unnecessary processing.
Configuration and Overhead
Certain configuration options in the ParserOptions interface directly impact performance. Developers can tune these settings to balance accuracy and speed.
| Option | Performance Impact | Description |
|---|---|---|
lowerCaseAttributeNames | High | When enabled, attribute names are lowercased using .toLowerCase(). |
decodeEntities | Moderate | Decodes entities (e.g., &). Disabling this allows the tokenizer to fast-forward past ampersands. |
xmlMode | Low | Switches logic between HTML-specific rules (like void elements) and strict XML rules. |
Sources: src/Parser.ts:186-218, src/Tokenizer.ts:397-400
Casing and Logic Handling
The parser maintains sets and maps for rapid lookup of tag behaviors (e.g., void elements, self-closing tags, and implicit closes).
Sources: src/Parser.ts:7-78, src/Parser.ts:366-385
Stream-Based Processing
htmlparser2 supports high-performance streaming through specialized interfaces. This allows processing large files without loading them entirely into memory.
WritableStream: A Node.js compatible Writable stream wrapper.WebWritableStream: A wrapper for the Web Streams API.pause()andresume(): These methods in bothParserandTokenizerallow for backpressure management, preventing the parser from overwhelming the system during high-load scenarios.
Sources: README.md:126-140, src/Parser.ts:705-728, src/Tokenizer.ts:386-395
Pausing Logic
The following sequence diagram shows how the parser handles pausing to maintain system stability.
Summary
htmlparser2 achieves its leading performance by prioritizing a lightweight, callback-driven architecture and a highly optimized tokenizer state machine. By utilizing fast-forwarding techniques for text nodes and minimizing memory allocations through buffer management and deferred string slicing, it remains the most efficient choice for high-volume HTML and XML processing in JavaScript environments.
Sources: README.md:12-14, README.md:204-222, src/Parser.ts:639-659