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