@@ -100,6 +100,7 @@ const FORWARD_SLASH = /\//g;
100100
101101const context = Symbol ( 'context' ) ;
102102const searchParams = Symbol ( 'query' ) ;
103+ const kDirty = Symbol ( 'dirty' ) ;
103104
104105const updateActions = {
105106 kProtocol : 0 ,
@@ -224,11 +225,12 @@ class URLSearchParams {
224225 } else {
225226 // USVString
226227 init = toUSVString ( init ) ;
227- initSearchParams ( this , init ) ;
228+ this [ searchParams ] = init ? parseParams ( init ) : [ ] ;
228229 }
229230
230231 // "associated url object"
231232 this [ context ] = null ;
233+ this [ kDirty ] = false ;
232234 }
233235
234236 [ inspect . custom ] ( recurseTimes , ctx ) {
@@ -604,11 +606,34 @@ class URL {
604606 ctx . password = password ;
605607 ctx . port = port ;
606608 ctx . hash = hash ;
607- if ( ! this [ searchParams ] ) { // Invoked from URL constructor
608- this [ searchParams ] = new URLSearchParams ( ) ;
609+ if ( this [ searchParams ] ) {
610+ // Update `kDirty` property to recalculate searchParams on access.
611+ // This is done to reduce the overhead of initializing the URL.
612+ this [ searchParams ] [ kDirty ] = true ;
613+ }
614+ } ;
615+
616+ #onSearchUpdate = ( href , origin , protocol , hostname , pathname ,
617+ search , username , password , port , hash ) => {
618+ const ctx = this [ context ] ;
619+ ctx . href = href ;
620+ ctx . origin = origin ;
621+ ctx . protocol = protocol ;
622+ ctx . hostname = hostname ;
623+ ctx . pathname = pathname ;
624+ ctx . search = search ;
625+ ctx . username = username ;
626+ ctx . password = password ;
627+ ctx . port = port ;
628+ ctx . hash = hash ;
629+
630+ if ( this [ searchParams ] == null ) {
631+ this [ searchParams ] = new URLSearchParams ( this [ context ] . search ) ;
609632 this [ searchParams ] [ context ] = this ;
633+ } else {
634+ this [ searchParams ] [ searchParams ] = this [ context ] . search ? parseParams ( this [ context ] . search ) : [ ] ;
635+ this [ searchParams ] [ kDirty ] = false ;
610636 }
611- initSearchParams ( this [ searchParams ] , ctx . search ) ;
612637 } ;
613638
614639 toString ( ) {
@@ -729,18 +754,25 @@ class URL {
729754 return this [ context ] . search ;
730755 }
731756
732- set search ( search ) {
757+ set search ( value ) {
733758 if ( ! isURLThis ( this ) )
734759 throw new ERR_INVALID_THIS ( 'URL' ) ;
735- search = toUSVString ( search ) ;
736- updateUrl ( this [ context ] . href , updateActions . kSearch , search , this . #onParseComplete) ;
737- initSearchParams ( this [ searchParams ] , this [ context ] . search ) ;
760+ updateUrl ( this [ context ] . href , updateActions . kSearch , toUSVString ( value ) , this . #onSearchUpdate) ;
738761 }
739762
740763 // readonly
741764 get searchParams ( ) {
742765 if ( ! isURLThis ( this ) )
743766 throw new ERR_INVALID_THIS ( 'URL' ) ;
767+ // Create URLSearchParams on demand to greatly improve the URL performance.
768+ if ( this [ searchParams ] == null ) {
769+ this [ searchParams ] = new URLSearchParams ( this [ context ] . search ) ;
770+ this [ searchParams ] [ context ] = this ;
771+ } else if ( this [ searchParams ] [ kDirty ] ) {
772+ const updated = this [ context ] . search ;
773+ this [ searchParams ] [ searchParams ] = updated ? parseParams ( updated ) : [ ] ;
774+ this [ searchParams ] [ kDirty ] = false ;
775+ }
744776 return this [ searchParams ] ;
745777 }
746778
@@ -815,14 +847,6 @@ ObjectDefineProperties(URL, {
815847 revokeObjectURL : kEnumerableProperty ,
816848} ) ;
817849
818- function initSearchParams ( url , init ) {
819- if ( ! init ) {
820- url [ searchParams ] = [ ] ;
821- return ;
822- }
823- url [ searchParams ] = parseParams ( init ) ;
824- }
825-
826850// application/x-www-form-urlencoded parser
827851// Ref: https://url.spec.whatwg.org/#concept-urlencoded-parser
828852function parseParams ( qs ) {
@@ -1141,8 +1165,7 @@ function domainToUnicode(domain) {
11411165function urlToHttpOptions ( url ) {
11421166 const options = {
11431167 protocol : url . protocol ,
1144- hostname : typeof url . hostname === 'string' &&
1145- StringPrototypeStartsWith ( url . hostname , '[' ) ?
1168+ hostname : url . hostname && StringPrototypeStartsWith ( url . hostname , '[' ) ?
11461169 StringPrototypeSlice ( url . hostname , 1 , - 1 ) :
11471170 url . hostname ,
11481171 hash : url . hash ,
@@ -1313,6 +1336,6 @@ module.exports = {
13131336 domainToASCII,
13141337 domainToUnicode,
13151338 urlToHttpOptions,
1316- searchParamsSymbol : searchParams ,
13171339 encodeStr,
1340+ isURLThis,
13181341} ;
0 commit comments