Skip to content

url: speed up URLSearchParams - #22

Draft
anonrig wants to merge 2 commits into
mainfrom
cursor/url-searchparams-performance-603e
Draft

url: speed up URLSearchParams#22
anonrig wants to merge 2 commits into
mainfrom
cursor/url-searchparams-performance-603e

Conversation

@anonrig

@anonrig anonrig commented Aug 18, 2026

Copy link
Copy Markdown
Owner

This speeds up WHATWG URLSearchParams without changing observable behavior.

Independent of the new URL() parse PR.

What changed

  • Parse: walk & / = with indexOf instead of a per-character state machine. When the input has no + or %, each component is a slice of the original string. Percent-decoding still runs only when a complete %HH sequence exists, so lone % and fake sequences like stay intact.
  • USVString: skip `${value}` when the value is already a string (constructor, append/get/set/has/delete).
  • Serialize: cache toString() until the list mutates; join encoded pairs instead of repeated +=.
  • Tests: test/parallel/test-whatwg-url-searchparams-fast-path.js covers leading ?, empty pairs, + / percent-decoding, invalid %, mutation cache invalidation, copy constructor isolation, record/sequence init, unpaired surrogates, and fake percent-encoding.

Tests

  • All test/parallel/test-whatwg-url-custom-searchparams*.js plus the new fast-path file
  • WPT test/wpt/test-url.js: 5107 passed, 0 unexpected failures

Local benches

Same binary family, both run with --no-node-snapshot (new JS is not in the V8 snapshot). Rates in ops/s:

Benchmark Before After
new URLSearchParams(string) noencode ~6.9M ~7.3M
new URLSearchParams(string) encodemany 6.9M 7.5M
new URLSearchParams(iterable) 9.9M 10.3M
toString() noencode (repeated) 7.7M ~213M
toString() encodemany (repeated) 4.9M ~200M
get() ~75M ~85M
has() ~52M ~59M

The large toString() jump is the serialization cache: the common “build params, stringify many times / read URL.href” path no longer re-encodes an unchanged list.

Ada already has a C url_search_params API. This keeps the implementation in JS to avoid a JS/C++ call on every get/append.

Assisted-by: Cursor

Open in Web Open in Cursor 

@cursor
cursor Bot force-pushed the cursor/url-searchparams-performance-603e branch 2 times, most recently from e18874e to 9863db8 Compare August 18, 2026 12:49
Parse query strings with indexOf instead of a per-character state
machine, skip ToString when values are already strings, cache
toString() until the list mutates, and join serialized pairs.

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Cursor
Leave lone '%' and non-hex percent sequences intact so serialization
matches the previous parser, and use native indexOf/slice/push on
the query-string hot path.

Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Cursor
@cursor
cursor Bot force-pushed the cursor/url-searchparams-performance-603e branch 3 times, most recently from 18331fb to eb812ac Compare August 18, 2026 18:43
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.

1 participant