Skip to content

Commit cfe7a49

Browse files
committed
url: improve URLSearchParams creation performance
1 parent 1640aeb commit cfe7a49

File tree

2 files changed

+38
-24
lines changed

2 files changed

+38
-24
lines changed

lib/internal/url.js

+34-24
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const {
44
Array,
5+
ArrayIsArray,
56
ArrayPrototypeJoin,
67
ArrayPrototypeMap,
78
ArrayPrototypePush,
@@ -150,52 +151,64 @@ function isURLSearchParams(self) {
150151
}
151152

152153
class URLSearchParams {
154+
[searchParams] = [];
155+
156+
// "associated url object"
157+
[context] = null;
158+
153159
// URL Standard says the default value is '', but as undefined and '' have
154160
// the same result, undefined is used to prevent unnecessary parsing.
155161
// Default parameter is necessary to keep URLSearchParams.length === 0 in
156162
// accordance with Web IDL spec.
157163
constructor(init = undefined) {
158-
if (init === null || init === undefined) {
159-
this[searchParams] = [];
164+
if (init == null) {
165+
// Do nothing
160166
} else if (typeof init === 'object' || typeof init === 'function') {
161167
const method = init[SymbolIterator];
162168
if (method === this[SymbolIterator]) {
163169
// While the spec does not have this branch, we can use it as a
164170
// shortcut to avoid having to go through the costly generic iterator.
165171
const childParams = init[searchParams];
166172
this[searchParams] = childParams.slice();
167-
} else if (method !== null && method !== undefined) {
173+
} else if (method != null) {
168174
if (typeof method !== 'function') {
169175
throw new ERR_ARG_NOT_ITERABLE('Query pairs');
170176
}
171177

172178
// Sequence<sequence<USVString>>
173-
// Note: per spec we have to first exhaust the lists then process them
174-
const pairs = [];
175179
for (const pair of init) {
176-
if ((typeof pair !== 'object' && typeof pair !== 'function') ||
177-
pair === null ||
178-
typeof pair[SymbolIterator] !== 'function') {
180+
if (pair == null) {
179181
throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]');
180-
}
181-
const convertedPair = [];
182-
for (const element of pair)
183-
ArrayPrototypePush(convertedPair, toUSVString(element));
184-
ArrayPrototypePush(pairs, convertedPair);
185-
}
182+
} else if (ArrayIsArray(pair)) {
183+
// If innerSequence's size is not 2, then throw a TypeError.
184+
if (pair.length !== 2) {
185+
throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]');
186+
}
187+
// Append (innerSequence[0], innerSequence[1]) to querys list.
188+
ArrayPrototypePush(this[searchParams], toUSVString(pair[0]), toUSVString(pair[1]));
189+
} else {
190+
if (((typeof pair !== 'object' && typeof pair !== 'function') ||
191+
typeof pair[SymbolIterator] !== 'function')) {
192+
throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]');
193+
}
186194

187-
this[searchParams] = [];
188-
for (const pair of pairs) {
189-
if (pair.length !== 2) {
190-
throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]');
195+
let length = 0;
196+
197+
for (const element of pair) {
198+
length++;
199+
ArrayPrototypePush(this[searchParams], element);
200+
}
201+
202+
// If innerSequence's size is not 2, then throw a TypeError.
203+
if (length !== 2) {
204+
throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]');
205+
}
191206
}
192-
ArrayPrototypePush(this[searchParams], pair[0], pair[1]);
193207
}
194208
} else {
195209
// Record<USVString, USVString>
196210
// Need to use reflection APIs for full spec compliance.
197211
const visited = {};
198-
this[searchParams] = [];
199212
const keys = ReflectOwnKeys(init);
200213
for (let i = 0; i < keys.length; i++) {
201214
const key = keys[i];
@@ -217,13 +230,10 @@ class URLSearchParams {
217230
}
218231
}
219232
} else {
220-
// USVString
233+
// https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
221234
init = toUSVString(init);
222235
this[searchParams] = init ? parseParams(init) : [];
223236
}
224-
225-
// "associated url object"
226-
this[context] = null;
227237
}
228238

229239
[inspect.custom](recurseTimes, ctx) {

test/parallel/test-whatwg-url-custom-searchparams-constructor.js

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ function makeIterableFunc(array) {
4747
assert.throws(() => new URLSearchParams([null]), tupleError);
4848
assert.throws(() => new URLSearchParams([{ [Symbol.iterator]: 42 }]),
4949
tupleError);
50+
51+
assert.throws(() => new URLSearchParams(
52+
makeIterableFunc([['key', 'val', 'val2']])
53+
), tupleError);
5054
}
5155

5256
{

0 commit comments

Comments
 (0)