From 74a74c7605fcc9b912cfbe8c6c0ec63e24edd47d Mon Sep 17 00:00:00 2001 From: Roberto Bianchi Date: Tue, 20 Oct 2026 11:33:15 +0200 Subject: [PATCH 1/3] url: use indexed appends in search params getAll Use indexed writes when collecting matching parameter values. This improves getAll throughput without changing result order. Signed-off-by: Roberto Bianchi --- benchmark/url/url-searchparams-getAll.js | 46 +++++++++++++++++++ lib/internal/url.js | 2 +- ...-whatwg-url-searchparams-getall-results.js | 24 ++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 benchmark/url/url-searchparams-getAll.js create mode 100644 test/parallel/test-whatwg-url-searchparams-getall-results.js diff --git a/benchmark/url/url-searchparams-getAll.js b/benchmark/url/url-searchparams-getAll.js new file mode 100644 index 000000000000..741bdee02d2e --- /dev/null +++ b/benchmark/url/url-searchparams-getAll.js @@ -0,0 +1,46 @@ +'use strict'; + +const common = require('../common'); +const assert = require('node:assert'); + +const bench = common.createBenchmark(main, { + n: [1e6], + size: [4, 32, 256], + matches: ['none', 'one', 'half', 'all'], + mode: ['read', 'construct'], +}); + +function main({ n, size, matches, mode }) { + const params = new URLSearchParams(); + const expected = []; + for (let index = 0; index < size; index++) { + const match = matches === 'all' || + (matches === 'half' && index % 2 === 0) || + (matches === 'one' && index === size - 1); + const value = `${index}`; + params.append(match ? 'target' : `key${index}`, value); + if (match) expected.push(value); + } + + const query = params.toString(); + let checksum = 0; + let result; + bench.start(); + if (mode === 'read') { + for (let iteration = 0; iteration < n; iteration++) { + result = params.getAll('target'); + checksum += result.length; + if (result.length !== 0) checksum += result[result.length - 1].length; + } + } else { + for (let iteration = 0; iteration < n; iteration++) { + result = new URLSearchParams(query).getAll('target'); + checksum += result.length; + if (result.length !== 0) checksum += result[result.length - 1].length; + } + } + bench.end(n); + assert.deepStrictEqual(result, expected); + assert.strictEqual(checksum, n * (expected.length + + (expected.length === 0 ? 0 : expected[expected.length - 1].length))); +} diff --git a/lib/internal/url.js b/lib/internal/url.js index 8c04ac70c07c..ea19875859c8 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -624,7 +624,7 @@ class URLSearchParams { const { length } = list; for (let i = 0; i < length; i += 2) { if (list[i] === name) { - ArrayPrototypePush(values, list[i + 1]); + values[values.length] = list[i + 1]; } } return values; diff --git a/test/parallel/test-whatwg-url-searchparams-getall-results.js b/test/parallel/test-whatwg-url-searchparams-getall-results.js new file mode 100644 index 000000000000..9de3d9a75e0e --- /dev/null +++ b/test/parallel/test-whatwg-url-searchparams-getall-results.js @@ -0,0 +1,24 @@ +'use strict'; + +require('../common'); +const assert = require('node:assert'); + +for (const size of [0, 1, 4, 32, 256]) { + const params = new URLSearchParams(); + const expected = []; + for (let index = 0; index < size; index++) { + params.append('other', `${index}`); + const value = index % 2 === 0 ? '' : `value${index}`; + params.append('target', value); + expected.push(value); + } + + const result = params.getAll('target'); + assert.deepStrictEqual(result, expected); + result.push('extra'); + result[0] = 'changed'; + assert.deepStrictEqual(params.getAll('target'), expected); + params.append('target', 'last'); + assert.deepStrictEqual(params.getAll('target'), [...expected, 'last']); + assert.deepStrictEqual(params.getAll('missing'), []); +} From 2f1f98e952ef85941953790718178129698197a3 Mon Sep 17 00:00:00 2001 From: Roberto Bianchi Date: Mon, 26 Oct 2026 11:17:14 +0100 Subject: [PATCH 2/3] update Signed-off-by: Roberto Bianchi --- ...-whatwg-url-searchparams-getall-results.js | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 test/parallel/test-whatwg-url-searchparams-getall-results.js diff --git a/test/parallel/test-whatwg-url-searchparams-getall-results.js b/test/parallel/test-whatwg-url-searchparams-getall-results.js deleted file mode 100644 index 9de3d9a75e0e..000000000000 --- a/test/parallel/test-whatwg-url-searchparams-getall-results.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -require('../common'); -const assert = require('node:assert'); - -for (const size of [0, 1, 4, 32, 256]) { - const params = new URLSearchParams(); - const expected = []; - for (let index = 0; index < size; index++) { - params.append('other', `${index}`); - const value = index % 2 === 0 ? '' : `value${index}`; - params.append('target', value); - expected.push(value); - } - - const result = params.getAll('target'); - assert.deepStrictEqual(result, expected); - result.push('extra'); - result[0] = 'changed'; - assert.deepStrictEqual(params.getAll('target'), expected); - params.append('target', 'last'); - assert.deepStrictEqual(params.getAll('target'), [...expected, 'last']); - assert.deepStrictEqual(params.getAll('missing'), []); -} From 5fff1bc73ec537a38a3c11904aee70e3d46558a4 Mon Sep 17 00:00:00 2001 From: Roberto Bianchi Date: Mon, 26 Oct 2026 11:28:56 +0100 Subject: [PATCH 3/3] update Signed-off-by: Roberto Bianchi --- benchmark/url/url-searchparams-getAll.js | 46 ------------------------ 1 file changed, 46 deletions(-) delete mode 100644 benchmark/url/url-searchparams-getAll.js diff --git a/benchmark/url/url-searchparams-getAll.js b/benchmark/url/url-searchparams-getAll.js deleted file mode 100644 index 741bdee02d2e..000000000000 --- a/benchmark/url/url-searchparams-getAll.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -const common = require('../common'); -const assert = require('node:assert'); - -const bench = common.createBenchmark(main, { - n: [1e6], - size: [4, 32, 256], - matches: ['none', 'one', 'half', 'all'], - mode: ['read', 'construct'], -}); - -function main({ n, size, matches, mode }) { - const params = new URLSearchParams(); - const expected = []; - for (let index = 0; index < size; index++) { - const match = matches === 'all' || - (matches === 'half' && index % 2 === 0) || - (matches === 'one' && index === size - 1); - const value = `${index}`; - params.append(match ? 'target' : `key${index}`, value); - if (match) expected.push(value); - } - - const query = params.toString(); - let checksum = 0; - let result; - bench.start(); - if (mode === 'read') { - for (let iteration = 0; iteration < n; iteration++) { - result = params.getAll('target'); - checksum += result.length; - if (result.length !== 0) checksum += result[result.length - 1].length; - } - } else { - for (let iteration = 0; iteration < n; iteration++) { - result = new URLSearchParams(query).getAll('target'); - checksum += result.length; - if (result.length !== 0) checksum += result[result.length - 1].length; - } - } - bench.end(n); - assert.deepStrictEqual(result, expected); - assert.strictEqual(checksum, n * (expected.length + - (expected.length === 0 ? 0 : expected[expected.length - 1].length))); -}