@@ -62,6 +62,7 @@ const kWeakHandler = Symbol('kWeak');
6262const kResistStopPropagation = Symbol ( 'kResistStopPropagation' ) ;
6363
6464const kHybridDispatch = SymbolFor ( 'nodejs.internal.kHybridDispatch' ) ;
65+ const kRemoveWeakListenerHelper = Symbol ( 'nodejs.internal.removeWeakListenerHelper' ) ;
6566const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
6667const kNewListener = Symbol ( 'kNewListener' ) ;
6768const kRemoveListener = Symbol ( 'kRemoveListener' ) ;
@@ -392,7 +393,7 @@ let weakListenersState = null;
392393let objectToWeakListenerMap = null ;
393394function weakListeners ( ) {
394395 weakListenersState ??= new SafeFinalizationRegistry (
395- ( listener ) => listener . remove ( ) ,
396+ ( { eventTarget , listener, eventType } ) => eventTarget . deref ( ) ?. [ kRemoveWeakListenerHelper ] ( eventType , listener ) ,
396397 ) ;
397398 objectToWeakListenerMap ??= new SafeWeakMap ( ) ;
398399 return { registry : weakListenersState , map : objectToWeakListenerMap } ;
@@ -414,7 +415,7 @@ const kFlagResistStopPropagation = 1 << 6;
414415// the linked list makes dispatching faster, even if adding/removing is
415416// slower.
416417class Listener {
417- constructor ( previous , listener , once , capture , passive ,
418+ constructor ( eventTarget , eventType , previous , listener , once , capture , passive ,
418419 isNodeStyleListener , weak , resistStopPropagation ) {
419420 this . next = undefined ;
420421 if ( previous !== undefined )
@@ -441,7 +442,13 @@ class Listener {
441442
442443 if ( this . weak ) {
443444 this . callback = new SafeWeakRef ( listener ) ;
444- weakListeners ( ) . registry . register ( listener , this , this ) ;
445+ weakListeners ( ) . registry . register ( listener , {
446+ __proto__ : null ,
447+ // Weak ref so the listener won't hold the eventTarget alive
448+ eventTarget : new SafeWeakRef ( eventTarget ) ,
449+ listener : this ,
450+ eventType,
451+ } , this ) ;
445452 // Make the retainer retain the listener in a WeakMap
446453 weakListeners ( ) . map . set ( weak , listener ) ;
447454 this . listener = this . callback ;
@@ -604,7 +611,7 @@ class EventTarget {
604611 if ( root === undefined ) {
605612 root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
606613 // This is the first handler in our linked list.
607- new Listener ( root , listener , once , capture , passive ,
614+ new Listener ( this , type , root , listener , once , capture , passive ,
608615 isNodeStyleListener , weak , resistStopPropagation ) ;
609616 this [ kNewListener ] (
610617 root . size ,
@@ -631,7 +638,7 @@ class EventTarget {
631638 return ;
632639 }
633640
634- new Listener ( previous , listener , once , capture , passive ,
641+ new Listener ( this , type , previous , listener , once , capture , passive ,
635642 isNodeStyleListener , weak , resistStopPropagation ) ;
636643 root . size ++ ;
637644 root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
@@ -674,6 +681,28 @@ class EventTarget {
674681 }
675682 }
676683
684+ [ kRemoveWeakListenerHelper ] ( type , listener ) {
685+ const root = this [ kEvents ] . get ( type ) ;
686+ if ( root === undefined || root . next === undefined )
687+ return ;
688+
689+ const capture = listener . capture === true ;
690+
691+ let handler = root . next ;
692+ while ( handler !== undefined ) {
693+ if ( handler === listener ) {
694+ handler . remove ( ) ;
695+ root . size -- ;
696+ if ( root . size === 0 )
697+ this [ kEvents ] . delete ( type ) ;
698+ // Undefined is passed as the listener as the listener was GCed
699+ this [ kRemoveListener ] ( root . size , type , undefined , capture ) ;
700+ break ;
701+ }
702+ handler = handler . next ;
703+ }
704+ }
705+
677706 /**
678707 * @param {Event } event
679708 */
0 commit comments