2
2
3
3
const {
4
4
Array,
5
+ ArrayIsArray,
5
6
ArrayPrototypeJoin,
6
7
ArrayPrototypeMap,
7
8
ArrayPrototypePush,
@@ -157,52 +158,74 @@ function isURLSearchParams(self) {
157
158
}
158
159
159
160
class URLSearchParams {
161
+ [ searchParams ] = [ ] ;
162
+
163
+ // "associated url object"
164
+ [ context ] = null ;
165
+
160
166
// URL Standard says the default value is '', but as undefined and '' have
161
167
// the same result, undefined is used to prevent unnecessary parsing.
162
168
// Default parameter is necessary to keep URLSearchParams.length === 0 in
163
169
// accordance with Web IDL spec.
164
170
constructor ( init = undefined ) {
165
- if ( init === null || init === undefined ) {
166
- this [ searchParams ] = [ ] ;
171
+ if ( init == null ) {
172
+ // Do nothing
167
173
} else if ( typeof init === 'object' || typeof init === 'function' ) {
168
174
const method = init [ SymbolIterator ] ;
169
175
if ( method === this [ SymbolIterator ] ) {
170
176
// While the spec does not have this branch, we can use it as a
171
177
// shortcut to avoid having to go through the costly generic iterator.
172
178
const childParams = init [ searchParams ] ;
173
179
this [ searchParams ] = childParams . slice ( ) ;
174
- } else if ( method !== null && method !== undefined ) {
180
+ } else if ( method != null ) {
181
+ // Sequence<sequence<USVString>>
175
182
if ( typeof method !== 'function' ) {
176
183
throw new ERR_ARG_NOT_ITERABLE ( 'Query pairs' ) ;
177
184
}
178
185
179
- // Sequence<sequence<USVString>>
180
- // Note: per spec we have to first exhaust the lists then process them
181
- const pairs = [ ] ;
186
+ // The following implementationd differs from the URL specification:
187
+ // Sequences must first be converted from ECMAScript objects before
188
+ // and operations are done on them, and the operation of converting
189
+ // the sequences would first exhaust the iterators. If the iterator
190
+ // returns something invalid in the middle, whether it would be called
191
+ // after that would be an observable change to the users.
192
+ // Exhausting the iterator and later converting them to USVString comes
193
+ // with a significant cost (~40-80%). In order optimize URLSearchParams
194
+ // creation duration, Node.js merges the iteration and converting
195
+ // iterations into a single iteration.
182
196
for ( const pair of init ) {
183
- if ( ( typeof pair !== 'object' && typeof pair !== 'function' ) ||
184
- pair === null ||
185
- typeof pair [ SymbolIterator ] !== 'function' ) {
197
+ if ( pair == null ) {
186
198
throw new ERR_INVALID_TUPLE ( 'Each query pair' , '[name, value]' ) ;
187
- }
188
- const convertedPair = [ ] ;
189
- for ( const element of pair )
190
- ArrayPrototypePush ( convertedPair , toUSVString ( element ) ) ;
191
- ArrayPrototypePush ( pairs , convertedPair ) ;
192
- }
199
+ } else if ( ArrayIsArray ( pair ) ) {
200
+ // If innerSequence's size is not 2, then throw a TypeError.
201
+ if ( pair . length !== 2 ) {
202
+ throw new ERR_INVALID_TUPLE ( 'Each query pair' , '[name, value]' ) ;
203
+ }
204
+ // Append (innerSequence[0], innerSequence[1]) to querys list.
205
+ ArrayPrototypePush ( this [ searchParams ] , toUSVString ( pair [ 0 ] ) , toUSVString ( pair [ 1 ] ) ) ;
206
+ } else {
207
+ if ( ( ( typeof pair !== 'object' && typeof pair !== 'function' ) ||
208
+ typeof pair [ SymbolIterator ] !== 'function' ) ) {
209
+ throw new ERR_INVALID_TUPLE ( 'Each query pair' , '[name, value]' ) ;
210
+ }
193
211
194
- this [ searchParams ] = [ ] ;
195
- for ( const pair of pairs ) {
196
- if ( pair . length !== 2 ) {
197
- throw new ERR_INVALID_TUPLE ( 'Each query pair' , '[name, value]' ) ;
212
+ let length = 0 ;
213
+
214
+ for ( const element of pair ) {
215
+ length ++ ;
216
+ ArrayPrototypePush ( this [ searchParams ] , toUSVString ( element ) ) ;
217
+ }
218
+
219
+ // If innerSequence's size is not 2, then throw a TypeError.
220
+ if ( length !== 2 ) {
221
+ throw new ERR_INVALID_TUPLE ( 'Each query pair' , '[name, value]' ) ;
222
+ }
198
223
}
199
- ArrayPrototypePush ( this [ searchParams ] , pair [ 0 ] , pair [ 1 ] ) ;
200
224
}
201
225
} else {
202
226
// Record<USVString, USVString>
203
227
// Need to use reflection APIs for full spec compliance.
204
228
const visited = { } ;
205
- this [ searchParams ] = [ ] ;
206
229
const keys = ReflectOwnKeys ( init ) ;
207
230
for ( let i = 0 ; i < keys . length ; i ++ ) {
208
231
const key = keys [ i ] ;
@@ -224,13 +247,10 @@ class URLSearchParams {
224
247
}
225
248
}
226
249
} else {
227
- // USVString
250
+ // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
228
251
init = toUSVString ( init ) ;
229
252
initSearchParams ( this , init ) ;
230
253
}
231
-
232
- // "associated url object"
233
- this [ context ] = null ;
234
254
}
235
255
236
256
[ inspect . custom ] ( recurseTimes , ctx ) {
0 commit comments