@@ -58,6 +58,7 @@ const kWeakHandler = Symbol('kWeak');
58
58
const kResistStopPropagation = Symbol ( 'kResistStopPropagation' ) ;
59
59
60
60
const kHybridDispatch = SymbolFor ( 'nodejs.internal.kHybridDispatch' ) ;
61
+ const kRemoveWeakListenerHelper = Symbol ( 'nodejs.internal.removeWeakListenerHelper' ) ;
61
62
const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
62
63
const kNewListener = Symbol ( 'kNewListener' ) ;
63
64
const kRemoveListener = Symbol ( 'kRemoveListener' ) ;
@@ -406,7 +407,7 @@ let weakListenersState = null;
406
407
let objectToWeakListenerMap = null ;
407
408
function weakListeners ( ) {
408
409
weakListenersState ??= new SafeFinalizationRegistry (
409
- ( listener ) => listener . remove ( ) ,
410
+ ( { eventTarget , listener, eventType } ) => eventTarget . deref ( ) ?. [ kRemoveWeakListenerHelper ] ( eventType , listener ) ,
410
411
) ;
411
412
objectToWeakListenerMap ??= new SafeWeakMap ( ) ;
412
413
return { registry : weakListenersState , map : objectToWeakListenerMap } ;
@@ -428,7 +429,7 @@ const kFlagResistStopPropagation = 1 << 6;
428
429
// the linked list makes dispatching faster, even if adding/removing is
429
430
// slower.
430
431
class Listener {
431
- constructor ( previous , listener , once , capture , passive ,
432
+ constructor ( eventTarget , eventType , previous , listener , once , capture , passive ,
432
433
isNodeStyleListener , weak , resistStopPropagation ) {
433
434
this . next = undefined ;
434
435
if ( previous !== undefined )
@@ -455,7 +456,13 @@ class Listener {
455
456
456
457
if ( this . weak ) {
457
458
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 ) ;
459
466
// Make the retainer retain the listener in a WeakMap
460
467
weakListeners ( ) . map . set ( weak , listener ) ;
461
468
this . listener = this . callback ;
@@ -621,7 +628,7 @@ class EventTarget {
621
628
if ( root === undefined ) {
622
629
root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
623
630
// 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 ,
625
632
isNodeStyleListener , weak , resistStopPropagation ) ;
626
633
this [ kNewListener ] (
627
634
root . size ,
@@ -648,7 +655,7 @@ class EventTarget {
648
655
return ;
649
656
}
650
657
651
- new Listener ( previous , listener , once , capture , passive ,
658
+ new Listener ( this , type , previous , listener , once , capture , passive ,
652
659
isNodeStyleListener , weak , resistStopPropagation ) ;
653
660
root . size ++ ;
654
661
root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
@@ -691,6 +698,28 @@ class EventTarget {
691
698
}
692
699
}
693
700
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
+
694
723
/**
695
724
* @param {Event } event
696
725
*/
0 commit comments