mirror of
https://github.com/nodejs/node.git
synced 2026-10-10 18:59:49 -04:00
url: create URLSearchParams collision map lazily
Object property keys are already unique unless USVString normalization changes a key. Avoid allocating and updating a SafeMap for ordinary record keys. Create and backfill it when normalization first changes a key. This improves object construction by 10% to 25% in the measured cases and reduces allocation by about 31% for a ten-property record. Assisted-by: Amp Signed-off-by: Romain Lanz <romain.lanz@pm.me> PR-URL: https://github.com/nodejs/node/pull/65801 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
1 parent
0551dee5f9
commit
464cbbda8a
2 files changed
+28
-3
No files matched your search
+15
-3
@@ -447,7 +447,9 @@ class URLSearchParams {
|
||||
} else {
|
||||
// Record<USVString, USVString>
|
||||
// Need to use reflection APIs for full spec compliance.
|
||||
const visited = new SafeMap();
|
||||
// Object keys are unique, but USVString normalization may merge
|
||||
// distinct keys. Lazily track normalized keys if a key changes.
|
||||
let visited;
|
||||
const keys = ReflectOwnKeys(init);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
@@ -456,8 +458,18 @@ class URLSearchParams {
|
||||
const typedKey = toUSVString(key);
|
||||
const typedValue = toUSVString(init[key]);
|
||||
|
||||
// Two different keys may become the same USVString after normalization.
|
||||
// In that case, we retain the later one. Refer to WPT.
|
||||
if (visited === undefined && typedKey === key) {
|
||||
ArrayPrototypePush(this.#searchParams, typedKey, typedValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visited === undefined) {
|
||||
visited = new SafeMap();
|
||||
for (let j = 0; j < this.#searchParams.length; j += 2) {
|
||||
visited.set(this.#searchParams[j], j + 1);
|
||||
}
|
||||
}
|
||||
|
||||
const keyIdx = visited.get(typedKey);
|
||||
if (keyIdx !== undefined) {
|
||||
this.#searchParams[keyIdx] = typedValue;
|
||||
|
||||
@@ -47,6 +47,19 @@ function makeIterableFunc(array) {
|
||||
params = new URLSearchParams({ hasOwnProperty: 1 });
|
||||
assert.strictEqual(params.get('hasOwnProperty'), '1');
|
||||
assert.strictEqual(params.toString(), 'hasOwnProperty=1');
|
||||
// A malformed key can collide with a valid key collected before the map
|
||||
// exists.
|
||||
params = new URLSearchParams({
|
||||
'before': '0',
|
||||
'\uFFFDx': 'first',
|
||||
'\uD835x': 'last',
|
||||
'after': '3'
|
||||
});
|
||||
assert.deepStrictEqual([...params], [
|
||||
['before', '0'],
|
||||
['\uFFFDx', 'last'],
|
||||
['after', '3'],
|
||||
]);
|
||||
assert.throws(() => new URLSearchParams([[1]]), tupleError);
|
||||
assert.throws(() => new URLSearchParams([[1, 2, 3]]), tupleError);
|
||||
assert.throws(() => new URLSearchParams({ [Symbol('test')]: 42 }),
|
||||
|
||||
Reference in new issue
Block a user