@@ -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 ( ) {
394395weakListenersState ??= new SafeFinalizationRegistry (
395- ( listener ) => listener . remove ( ) ,
396+ ( { eventTarget , listener, eventType } ) => eventTarget . deref ( ) ?. [ kRemoveWeakListenerHelper ] ( eventType , listener ) ,
396397) ;
397398objectToWeakListenerMap ??= new SafeWeakMap ( ) ;
398399return { 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 ,
418419isNodeStyleListener , weak , resistStopPropagation ) {
419420this . next = undefined ;
420421if ( previous !== undefined )
@@ -441,7 +442,13 @@ class Listener{
441442
442443if ( this . weak ) {
443444this . 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
446453weakListeners ( ) . map . set ( weak , listener ) ;
447454this . listener = this . callback ;
@@ -604,7 +611,7 @@ class EventTarget{
604611if ( root === undefined ) {
605612root = { 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 ,
608615isNodeStyleListener , weak , resistStopPropagation ) ;
609616this [ kNewListener ] (
610617root . size ,
@@ -631,7 +638,7 @@ class EventTarget{
631638return ;
632639}
633640
634- new Listener ( previous , listener , once , capture , passive ,
641+ new Listener ( this , type , previous , listener , once , capture , passive ,
635642isNodeStyleListener , weak , resistStopPropagation ) ;
636643root . size ++ ;
637644root . 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