@@ -62,6 +62,7 @@ const kWeakHandler = Symbol('kWeak');
62
62
const kResistStopPropagation = Symbol ( 'kResistStopPropagation' ) ;
63
63
64
64
const kHybridDispatch = SymbolFor ( 'nodejs.internal.kHybridDispatch' ) ;
65
+ const kRemoveWeakListenerHelper = Symbol ( 'nodejs.internal.removeWeakListenerHelper' ) ;
65
66
const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
66
67
const kNewListener = Symbol ( 'kNewListener' ) ;
67
68
const kRemoveListener = Symbol ( 'kRemoveListener' ) ;
@@ -410,7 +411,7 @@ let weakListenersState = null;
410
411
let objectToWeakListenerMap = null ;
411
412
function weakListeners ( ) {
412
413
weakListenersState ??= new SafeFinalizationRegistry (
413
- ( listener ) => listener . remove ( ) ,
414
+ ( { eventTarget , listener, eventType } ) => eventTarget . deref ( ) ?. [ kRemoveWeakListenerHelper ] ( eventType , listener ) ,
414
415
) ;
415
416
objectToWeakListenerMap ??= new SafeWeakMap ( ) ;
416
417
return { registry : weakListenersState , map : objectToWeakListenerMap } ;
@@ -432,7 +433,7 @@ const kFlagResistStopPropagation = 1 << 6;
432
433
// the linked list makes dispatching faster, even if adding/removing is
433
434
// slower.
434
435
class Listener {
435
- constructor ( previous , listener , once , capture , passive ,
436
+ constructor ( eventTarget , eventType , previous , listener , once , capture , passive ,
436
437
isNodeStyleListener , weak , resistStopPropagation ) {
437
438
this . next = undefined ;
438
439
if ( previous !== undefined )
@@ -459,7 +460,13 @@ class Listener {
459
460
460
461
if ( this . weak ) {
461
462
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 ) ;
463
470
// Make the retainer retain the listener in a WeakMap
464
471
weakListeners ( ) . map . set ( weak , listener ) ;
465
472
this . listener = this . callback ;
@@ -625,7 +632,7 @@ class EventTarget {
625
632
if ( root === undefined ) {
626
633
root = { size : 1 , next : undefined , resistStopPropagation : Boolean ( resistStopPropagation ) } ;
627
634
// 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 ,
629
636
isNodeStyleListener , weak , resistStopPropagation ) ;
630
637
this [ kNewListener ] (
631
638
root . size ,
@@ -652,7 +659,7 @@ class EventTarget {
652
659
return ;
653
660
}
654
661
655
- new Listener ( previous , listener , once , capture , passive ,
662
+ new Listener ( this , type , previous , listener , once , capture , passive ,
656
663
isNodeStyleListener , weak , resistStopPropagation ) ;
657
664
root . size ++ ;
658
665
root . resistStopPropagation ||= Boolean ( resistStopPropagation ) ;
@@ -695,6 +702,28 @@ class EventTarget {
695
702
}
696
703
}
697
704
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
+
698
727
/**
699
728
* @param {Event } event
700
729
*/
0 commit comments