Skip to content

Refactor classNames scanner and add classList#2500

Merged
jhy merged 2 commits into
masterfrom
classnames
May 7, 2026
Merged

Refactor classNames scanner and add classList#2500
jhy merged 2 commits into
masterfrom
classnames

Conversation

@jhy

@jhy jhy commented May 7, 2026

Copy link
Copy Markdown
Owner

Improve throughput and allocation behavior in classNames() by replacing the regex split path with a small HTML-whitespace scanner.

Add classList() as an immutable snapshot API for callers that only need to read class names, with a more efficient empty result path for elements without classes.

Align classNames(), classList(), and hasClass() on the HTML whitespace definition for class attributes.

Benchmarks

classNames() Throughput:

Fixture Scope 1.22.2 New Gain
tiny all elements 36.0M ops/s 270.6M ops/s 652.1%
small all elements 39.1M ops/s 153.3M ops/s 291.6%
medium all elements 28.3M ops/s 144.5M ops/s 411.3%
large all elements 30.1M ops/s 63.2M ops/s 110.3%
x-large all elements 11.7M ops/s 22.1M ops/s 88.9%
small classed elements 35.1M ops/s 54.6M ops/s 55.3%
medium classed elements 18.3M ops/s 43.6M ops/s 137.8%
large classed elements 21.2M ops/s 26.2M ops/s 23.6%
x-large classed elements 9.7M ops/s 15.2M ops/s 56.8%

classNames() Allocation:

Fixture Scope 1.22.2 New Saving
tiny all elements 376 B/op 80.0 B/op 78.7%
small all elements 352 B/op 89.7 B/op 74.5%
medium all elements 460 B/op 93.1 B/op 79.8%
large all elements 376 B/op 104 B/op 72.3%
x-large all elements 544 B/op 203 B/op 62.7%
small classed elements 376 B/op 152 B/op 59.6%
medium classed elements 511 B/op 171 B/op 66.6%
large classed elements 376 B/op 152 B/op 59.6%
x-large classed elements 560 B/op 261 B/op 53.4%

classList() Baseline:

Fixture Scope classList() throughput classList() allocation
tiny all elements 1,355.8M ops/s ~0 B/op
small all elements 285.3M ops/s 3.2 B/op
medium all elements 215.6M ops/s 6.4 B/op
large all elements 112.4M ops/s 8.1 B/op
x-large all elements 26.1M ops/s 79.0 B/op
small classed elements 87.0M ops/s 24.0 B/op
medium classed elements 61.0M ops/s 44.8 B/op
large classed elements 40.2M ops/s 24.0 B/op
x-large classed elements 18.6M ops/s 117 B/op

Fixture Class Histogram:

Fixture Input Elements [class] elements 0 classes 1 class 2 classes 3 classes 4+ classes Avg classes / [class]
tiny 274 B 11 0 11 0 0 0 0 0.00
small 3.3 KB 45 6 39 6 0 0 0 1.00
medium 8.6 KB 160 22 138 19 3 0 0 1.14
large 496.3 KB 6,208 2,145 4,063 2,145 0 0 0 1.00
x-large 2.3 MB 10,310 7,347 2,963 3,435 1,594 1,245 1,073 2.20

(Single threaded performance, relative comparison)

jhy added 2 commits May 7, 2026 13:32
Improve throughput and allocation behavior in `classNames()` by replacing the regex split path with a small HTML-whitespace scanner.

Add `classList()` as an immutable snapshot API for callers that only need to read class names, with a more efficient empty result path for elements without classes.

Align `classNames()`, `classList()`, and `hasClass()` on the HTML whitespace definition for class attributes.
@jhy jhy added this to the 1.23.1 milestone May 7, 2026
@jhy jhy added the improvement An improvement / new feature idea label May 7, 2026
@jhy
jhy merged commit 3a767de into master May 7, 2026
22 checks passed
@jhy
jhy deleted the classnames branch May 7, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement An improvement / new feature idea

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant