22
33const {
44 Array,
5+ ArrayIsArray,
56 ArrayPrototypeJoin,
67 ArrayPrototypeMap,
78 ArrayPrototypePush,
@@ -156,52 +157,74 @@ function isURLSearchParams(self) {
156157}
157158
158159class URLSearchParams {
160+ [ searchParams ] = [ ] ;
161+
162+ // "associated url object"
163+ [ context ] = null ;
164+
159165 // URL Standard says the default value is '', but as undefined and '' have
160166 // the same result, undefined is used to prevent unnecessary parsing.
161167 // Default parameter is necessary to keep URLSearchParams.length === 0 in
162168 // accordance with Web IDL spec.
163169 constructor ( init = undefined ) {
164- if ( init === null || init === undefined ) {
165- this [ searchParams ] = [ ] ;
170+ if ( init == null ) {
171+ // Do nothing
166172 } else if ( typeof init === 'object' || typeof init === 'function' ) {
167173 const method = init [ SymbolIterator ] ;
168174 if ( method === this [ SymbolIterator ] ) {
169175 // While the spec does not have this branch, we can use it as a
170176 // shortcut to avoid having to go through the costly generic iterator.
171177 const childParams = init [ searchParams ] ;
172178 this [ searchParams ] = childParams . slice ( ) ;
173- } else if ( method !== null && method !== undefined ) {
179+ } else if ( method != null ) {
180+ // Sequence<sequence<USVString>>
174181 if ( typeof method !== 'function' ) {
175182 throw new ERR_ARG_NOT_ITERABLE ( 'Query pairs' ) ;
176183 }
177184
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.
181195 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 ) {
185197 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+ }
192210
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+ }
197222 }
198- ArrayPrototypePush ( this [ searchParams ] , pair [ 0 ] , pair [ 1 ] ) ;
199223 }
200224 } else {
201225 // Record<USVString, USVString>
202226 // Need to use reflection APIs for full spec compliance.
203227 const visited = { } ;
204- this [ searchParams ] = [ ] ;
205228 const keys = ReflectOwnKeys ( init ) ;
206229 for ( let i = 0 ; i < keys . length ; i ++ ) {
207230 const key = keys [ i ] ;
@@ -223,13 +246,10 @@ class URLSearchParams {
223246 }
224247 }
225248 } else {
226- // USVString
249+ // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
227250 init = toUSVString ( init ) ;
228251 this [ searchParams ] = init ? parseParams ( init ) : [ ] ;
229252 }
230-
231- // "associated url object"
232- this [ context ] = null ;
233253 }
234254
235255 [ inspect . custom ] ( recurseTimes , ctx ) {
0 commit comments