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