perf: optimize gobbleParens, specificity, and regex pattern caching#85
Open
TrevorBurnham wants to merge 1 commit into
Open
perf: optimize gobbleParens, specificity, and regex pattern caching#85TrevorBurnham wants to merge 1 commit into
TrevorBurnham wants to merge 1 commit into
Conversation
- gobbleParens: replace O(n²) string concatenation with a single slice - specificity: fix duplicate specificity() call in list selector handling - getArgumentPatternByType: cache compiled RegExp for pseudo-class/element patterns Benchmarked with bench.mjs across simple, moderate, heavy, and stress selectors. Combined effect: ~11% faster specificity/e2e, ~7% faster tokenize, ~2x faster specificity-from-AST. All 34 existing tests pass.
✅ Deploy Preview for parsel ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This CR adds a benchmark suite to parsel-js and applies three optimizations.
For context, I'm trying to get happy-dom to adopt parsel-js instead of its own regex-based CSS selector parser, which has known bugs that parsel-js fixes: capricorn86/happy-dom#2010 However, the lead maintainer is concerned about the performance hit. I'd love to see a world where JavaScript has CSS selector parser that's both fast and accurate! ⚡🎯
Changes
1.
gobbleParens— slice instead of string concatenationThe original built a result string character-by-character (
result += char), which creates a new string allocation on every iteration — O(n²) for long parenthesized expressions. Replaced with index tracking and a singletext.slice()call at the end.2.
specificity— remove duplicate computation for selector listsWhen computing specificity for a list selector (e.g.
div, #foo),specificity()was called twice per child selector:3.
getArgumentPatternByType— cache compiled RegExpEach call for
pseudo-classorpseudo-elementtypes was constructing a newRegExpvia string replacement. Since the token grammar is stable between calls, the compiled patterns are now cached in aMap.Benchmark results
Measured with
bench.mjs(included), which exercisestokenize,parse,stringify,specificity,walk, and end-to-end across 23 selectors of varying complexity. 5000 iterations per benchmark, 500 warmup, median reported.Optimizations evaluated but not included
nestTokenssingle-pass comma detection: Merging thefind()+ iteration into one pass showed no measurable improvement — token arrays are small enough that the extra scan is negligible.tokenizeBysplice avoidance: Replacing in-placesplicewith a two-array swap showed ~3% on tokenize but added complexity for minimal gain.Testing
All existing tests pass.