Skip to content

perf: skip quoted attribute values in one step (long SVG path data 4-5x faster) - #919

Merged
amitguptagwl merged 1 commit into
NaturalIntelligence:masterfrom
deadstrobe5:perf/attr-value-skip
Nov 13, 2026
Merged

amitguptagwl merged 1 commit into
NaturalIntelligence:masterfrom
deadstrobe5:perf/attr-value-skip

Conversation

@deadstrobe5

Copy link
Copy Markdown
Contributor

Purpose / Goal

Long attribute values are slow to parse. tagExpWithClosingIndex walks every character of a quoted value only to find its closing quote, and attrsRegx then reads the value with a lazy [\s\S]*? up to a backreference, which V8 runs much slower than a negated character class. SVG is the common case: path d attributes are often tens of KB.

This PR jumps over a quoted value with indexOf of its own quote character, and matches values with "([^"]*)"|'([^']*)' (the value now comes from group 3 or 4 through a small attrValue helper). Both stop at the first matching quote, as before, so the same strings reach entity decoding and the value processors. An unterminated quote still makes tagExpWithClosingIndex return undefined, and tabs inside a value are still left alone.

Same-process A/B on Node 24, ignoreAttributes: false, median of 7 alternating rounds:

input before after
SVG, 1 path of 2000 points (30 KB) 0.79 ms 0.16 ms
SVG, 20 such paths (592 KB) 14.5 ms 3.6 ms
2000 elements with 4 short attributes (122 KB) 38.9 ms 38.4 ms

The new spec covers long values that hold the other quote, >, /> and tabs, and passes on master too. A differential fuzz against master (random documents with mixed and unterminated quotes, tabs, boolean and unquoted attributes, CRLF, 9 option sets, 54,000 comparisons) gave identical output and identical errors.

Type

  • Bug Fix
  • Refactoring / Technology upgrade
  • New Feature

@amitguptagwl
amitguptagwl merged commit 339eaba into NaturalIntelligence:master Nov 13, 2026
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants