@@ -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' ) ;
@@ -410,7 +411,7 @@ let weakListenersState = null;
410411let objectToWeakListenerMap = null ;
411412function weakListeners ( ) {
412413 weakListenersState ??= new SafeFinalizationRegistry (
413- ( listener ) => listener . remove ( ) ,
414+ ( { eventTarget , listener, eventType } ) => eventTarget . deref ( ) ?. [ kRemoveWeakListenerHelper ] ( eventType , listener ) ,
414415 ) ;
415416 objectToWeakListenerMap ??= new SafeWeakMap ( ) ;
416417 return { registry : weakListenersState , map : objectToWeakListenerMap } ;
@@ -432,7 +433,7 @@ const kFlagResistStopPropagation = 1 << 6;
432433// the linked list makes dispatching faster, even if adding/removing is
433434// slower.
434435class Listener {
435- constructor ( previous , listener , once , capture , passive ,
436+ constructor ( eventTarget , eventType , previous , listener , once , capture , passive ,
436437 isNodeStyleListener , weak , resistStopPropagation ) {
437438 this . next = undefined ;
438439 if ( previous !== undefined )
@@ -459,7 +460,13 @@ class Listener {
459460
460461 if ( this . weak ) {
461462 this . callback = new SafeWeakRef ( listener ) ;
462- weakListeners ( ) . registry . register ( listener , this , this ) ;
463+ weakListeners ( ) . registry . register ( listener , {
464+ __proto__ : null ,
465+ // Weak ref so the listener won't hold the eventTarget alive
466+ eventTarget : new SafeWeakRef ( eventTarget ) ,
467+ listener : this ,
468+ eventType,
469+ } , this ) ;
463470 // Make the retainer retain the listener in a WeakMap
464471 weakListeners ( ) . map . set ( weak , listener ) ;
465472 this . listener = this . callback ;
@@ -625,7 +632,7 @@ class EventTarget {
625632 if ( root === undefined ) {
626633 root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
627634 // This is the first handler in our linked list.
628- new Listener ( root , listener , once , capture , passive ,
635+ new Listener ( this , type , root , listener , once , capture , passive ,
629636 isNodeStyleListener , weak , resistStopPropagation ) ;
630637 this [ kNewListener ] (
631638 root . size ,
@@ -652,7 +659,7 @@ class EventTarget {
652659 return ;
653660 }
654661
655- new Listener ( previous , listener , once , capture , passive ,
662+ new Listener ( this , type , previous , listener , once , capture , passive ,
656663 isNodeStyleListener , weak , resistStopPropagation ) ;
657664 root . size ++ ;
658665 root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
@@ -695,6 +702,28 @@ class EventTarget {
695702 }
696703 }
697704
705+ [ kRemoveWeakListenerHelper ] ( type , listener ) {
706+ const root = this [ kEvents ] . get ( type ) ;
707+ if ( root === undefined || root . next === undefined )
708+ return ;
709+
710+ const capture = listener . capture === true ;
711+
712+ let handler = root . next ;
713+ while ( handler !== undefined ) {
714+ if ( handler === listener ) {
715+ handler . remove ( ) ;
716+ root . size -- ;
717+ if ( root . size === 0 )
718+ this [ kEvents ] . delete ( type ) ;
719+ // Undefined is passed as the listener as the listener was GCed
720+ this [ kRemoveListener ] ( root . size , type , undefined , capture ) ;
721+ break ;
722+ }
723+ handler = handler . next ;
724+ }
725+ }
726+
698727 /**
699728 * @param {Event } event
700729 */
0 commit comments