@@ -58,6 +58,7 @@ const kWeakHandler = Symbol('kWeak');
5858const kResistStopPropagation = Symbol ( 'kResistStopPropagation' ) ;
5959
6060const kHybridDispatch = SymbolFor ( 'nodejs.internal.kHybridDispatch' ) ;
61+ const kRemoveWeakListenerHelper = Symbol ( 'nodejs.internal.removeWeakListenerHelper' ) ;
6162const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
6263const kNewListener = Symbol ( 'kNewListener' ) ;
6364const kRemoveListener = Symbol ( 'kRemoveListener' ) ;
@@ -406,7 +407,7 @@ let weakListenersState = null;
406407let objectToWeakListenerMap = null ;
407408function weakListeners ( ) {
408409 weakListenersState ??= new SafeFinalizationRegistry (
409- ( listener ) => listener . remove ( ) ,
410+ ( { eventTarget , listener, eventType } ) => eventTarget . deref ( ) ?. [ kRemoveWeakListenerHelper ] ( eventType , listener ) ,
410411 ) ;
411412 objectToWeakListenerMap ??= new SafeWeakMap ( ) ;
412413 return { registry : weakListenersState , map : objectToWeakListenerMap } ;
@@ -428,7 +429,7 @@ const kFlagResistStopPropagation = 1 << 6;
428429// the linked list makes dispatching faster, even if adding/removing is
429430// slower.
430431class Listener {
431- constructor ( previous , listener , once , capture , passive ,
432+ constructor ( eventTarget , eventType , previous , listener , once , capture , passive ,
432433 isNodeStyleListener , weak , resistStopPropagation ) {
433434 this . next = undefined ;
434435 if ( previous !== undefined )
@@ -455,7 +456,13 @@ class Listener {
455456
456457 if ( this . weak ) {
457458 this . callback = new SafeWeakRef ( listener ) ;
458- weakListeners ( ) . registry . register ( listener , this , this ) ;
459+ weakListeners ( ) . registry . register ( listener , {
460+ __proto__ : null ,
461+ // Weak ref so the listener won't hold the eventTarget alive
462+ eventTarget : new SafeWeakRef ( eventTarget ) ,
463+ listener : this ,
464+ eventType,
465+ } , this ) ;
459466 // Make the retainer retain the listener in a WeakMap
460467 weakListeners ( ) . map . set ( weak , listener ) ;
461468 this . listener = this . callback ;
@@ -621,7 +628,7 @@ class EventTarget {
621628 if ( root === undefined ) {
622629 root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
623630 // This is the first handler in our linked list.
624- new Listener ( root , listener , once , capture , passive ,
631+ new Listener ( this , type , root , listener , once , capture , passive ,
625632 isNodeStyleListener , weak , resistStopPropagation ) ;
626633 this [ kNewListener ] (
627634 root . size ,
@@ -648,7 +655,7 @@ class EventTarget {
648655 return ;
649656 }
650657
651- new Listener ( previous , listener , once , capture , passive ,
658+ new Listener ( this , type , previous , listener , once , capture , passive ,
652659 isNodeStyleListener , weak , resistStopPropagation ) ;
653660 root . size ++ ;
654661 root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
@@ -691,6 +698,28 @@ class EventTarget {
691698 }
692699 }
693700
701+ [ kRemoveWeakListenerHelper ] ( type , listener ) {
702+ const root = this [ kEvents ] . get ( type ) ;
703+ if ( root === undefined || root . next === undefined )
704+ return ;
705+
706+ const capture = listener . capture === true ;
707+
708+ let handler = root . next ;
709+ while ( handler !== undefined ) {
710+ if ( handler === listener ) {
711+ handler . remove ( ) ;
712+ root . size -- ;
713+ if ( root . size === 0 )
714+ this [ kEvents ] . delete ( type ) ;
715+ // Undefined is passed as the listener as the listener was GCed
716+ this [ kRemoveListener ] ( root . size , type , undefined , capture ) ;
717+ break ;
718+ }
719+ handler = handler . next ;
720+ }
721+ }
722+
694723 /**
695724 * @param {Event } event
696725 */
0 commit comments