From 3bb3f8cdbd97a90cbd35957bebb10e8cd6d67917 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Tue, 21 Mar 2023 09:39:58 -0400 Subject: [PATCH] url: improve URLSearchParams creation performance --- lib/internal/url.js | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index fe4dab1224be39..37b27384caec56 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -2,6 +2,7 @@ const { Array, + ArrayIsArray, ArrayPrototypeJoin, ArrayPrototypeMap, ArrayPrototypePush, @@ -150,13 +151,18 @@ function isURLSearchParams(self) { } class URLSearchParams { + [searchParams] = []; + + // "associated url object" + [context] = null; + // URL Standard says the default value is '', but as undefined and '' have // the same result, undefined is used to prevent unnecessary parsing. // Default parameter is necessary to keep URLSearchParams.length === 0 in // accordance with Web IDL spec. constructor(init = undefined) { - if (init === null || init === undefined) { - this[searchParams] = []; + if (init == null) { + // Do nothing } else if (typeof init === 'object' || typeof init === 'function') { const method = init[SymbolIterator]; if (method === this[SymbolIterator]) { @@ -164,38 +170,25 @@ class URLSearchParams { // shortcut to avoid having to go through the costly generic iterator. const childParams = init[searchParams]; this[searchParams] = childParams.slice(); - } else if (method !== null && method !== undefined) { + } else if (method != null) { if (typeof method !== 'function') { throw new ERR_ARG_NOT_ITERABLE('Query pairs'); } // Sequence> - // Note: per spec we have to first exhaust the lists then process them - const pairs = []; for (const pair of init) { - if ((typeof pair !== 'object' && typeof pair !== 'function') || - pair === null || - typeof pair[SymbolIterator] !== 'function') { + // If innerSequence's size is not 2, then throw a TypeError. + if (pair == null || !ArrayIsArray(pair) || pair.length !== 2) { throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]'); } - const convertedPair = []; - for (const element of pair) - ArrayPrototypePush(convertedPair, toUSVString(element)); - ArrayPrototypePush(pairs, convertedPair); - } - this[searchParams] = []; - for (const pair of pairs) { - if (pair.length !== 2) { - throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]'); - } - ArrayPrototypePush(this[searchParams], pair[0], pair[1]); + // Append (innerSequence[0], innerSequence[1]) to querys list. + ArrayPrototypePush(this[searchParams], toUSVString(pair[0]), toUSVString(pair[1])); } } else { // Record // Need to use reflection APIs for full spec compliance. const visited = {}; - this[searchParams] = []; const keys = ReflectOwnKeys(init); for (let i = 0; i < keys.length; i++) { const key = keys[i]; @@ -217,13 +210,10 @@ class URLSearchParams { } } } else { - // USVString + // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams init = toUSVString(init); this[searchParams] = init ? parseParams(init) : []; } - - // "associated url object" - this[context] = null; } [inspect.custom](recurseTimes, ctx) {