@@ -27,7 +27,6 @@ const {
27
27
ArrayPrototypeShift,
28
28
ArrayPrototypeSlice,
29
29
ArrayPrototypeSplice,
30
- ArrayFrom,
31
30
Boolean,
32
31
Error,
33
32
ErrorCaptureStackTrace,
@@ -64,7 +63,6 @@ const {
64
63
ERR_UNHANDLED_ERROR
65
64
} ,
66
65
} = require ( 'internal/errors' ) ;
67
- const getLinkedMap = require ( 'internal/linkedMap' ) ;
68
66
69
67
const {
70
68
validateAbortSignal,
@@ -388,19 +386,30 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
388
386
if ( handler === undefined )
389
387
return false ;
390
388
391
- const listeners = ArrayFrom ( handler ) ;
392
- const len = handler . length ;
393
- for ( let i = 0 ; i < len ; ++ i ) {
394
- const result = listeners [ i ] . apply ( this , args ) ;
389
+ if ( typeof handler === 'function' ) {
390
+ const result = handler . apply ( this , args ) ;
395
391
396
392
// We check if result is undefined first because that
397
393
// is the most common case so we do not pay any perf
398
- // penalty.
399
- // This code is duplicated because extracting it away
400
- // would make it non-inlineable.
394
+ // penalty
401
395
if ( result !== undefined && result !== null ) {
402
396
addCatch ( this , result , type , args ) ;
403
397
}
398
+ } else {
399
+ const len = handler . length ;
400
+ const listeners = arrayClone ( handler ) ;
401
+ for ( let i = 0 ; i < len ; ++ i ) {
402
+ const result = listeners [ i ] . apply ( this , args ) ;
403
+
404
+ // We check if result is undefined first because that
405
+ // is the most common case so we do not pay any perf
406
+ // penalty.
407
+ // This code is duplicated because extracting it away
408
+ // would make it non-inlineable.
409
+ if ( result !== undefined && result !== null ) {
410
+ addCatch ( this , result , type , args ) ;
411
+ }
412
+ }
404
413
}
405
414
406
415
return true ;
@@ -433,29 +442,36 @@ function _addListener(target, type, listener, prepend) {
433
442
434
443
if ( existing === undefined ) {
435
444
// Optimize the case of one listener. Don't need the extra array object.
436
- existing = events [ type ] = getLinkedMap ( ) . push ( listener ) ;
445
+ events [ type ] = listener ;
437
446
++ target . _eventsCount ;
438
- } else if ( prepend ) {
439
- existing . unshift ( listener ) ;
440
447
} else {
441
- existing . push ( listener ) ;
442
- }
448
+ if ( typeof existing === 'function' ) {
449
+ // Adding the second element, need to change to array.
450
+ existing = events [ type ] =
451
+ prepend ? [ listener , existing ] : [ existing , listener ] ;
452
+ // If we've already got an array, just append.
453
+ } else if ( prepend ) {
454
+ existing . unshift ( listener ) ;
455
+ } else {
456
+ existing . push ( listener ) ;
457
+ }
443
458
444
- // Check for listener leak
445
- m = _getMaxListeners ( target ) ;
446
- if ( m > 0 && existing . length > m && ! existing . warned ) {
447
- existing . warned = true ;
448
- // No error code for this since it is a Warning
449
- // eslint-disable-next-line no-restricted-syntax
450
- const w = new Error ( 'Possible EventEmitter memory leak detected. ' +
451
- `${ existing . length } ${ String ( type ) } listeners ` +
452
- `added to ${ inspect ( target , { depth : - 1 } ) } . Use ` +
453
- 'emitter.setMaxListeners() to increase limit' ) ;
454
- w . name = 'MaxListenersExceededWarning' ;
455
- w . emitter = target ;
456
- w . type = type ;
457
- w . count = existing . length ;
458
- process . emitWarning ( w ) ;
459
+ // Check for listener leak
460
+ m = _getMaxListeners ( target ) ;
461
+ if ( m > 0 && existing . length > m && ! existing . warned ) {
462
+ existing . warned = true ;
463
+ // No error code for this since it is a Warning
464
+ // eslint-disable-next-line no-restricted-syntax
465
+ const w = new Error ( 'Possible EventEmitter memory leak detected. ' +
466
+ `${ existing . length } ${ String ( type ) } listeners ` +
467
+ `added to ${ inspect ( target , { depth : - 1 } ) } . Use ` +
468
+ 'emitter.setMaxListeners() to increase limit' ) ;
469
+ w . name = 'MaxListenersExceededWarning' ;
470
+ w . emitter = target ;
471
+ w . type = type ;
472
+ w . count = existing . length ;
473
+ process . emitWarning ( w ) ;
474
+ }
459
475
}
460
476
461
477
return target ;
@@ -548,10 +564,39 @@ EventEmitter.prototype.removeListener =
548
564
const list = events [ type ] ;
549
565
if ( list === undefined )
550
566
return this ;
551
- if ( list ?. remove ( listener ) ) {
552
- if ( list . length === 0 ) {
567
+
568
+ if ( list === listener || list . listener === listener ) {
569
+ if ( -- this . _eventsCount === 0 )
570
+ this . _events = ObjectCreate ( null ) ;
571
+ else {
553
572
delete events [ type ] ;
573
+ if ( events . removeListener )
574
+ this . emit ( 'removeListener' , type , list . listener || listener ) ;
575
+ }
576
+ } else if ( typeof list !== 'function' ) {
577
+ let position = - 1 ;
578
+
579
+ for ( let i = list . length - 1 ; i >= 0 ; i -- ) {
580
+ if ( list [ i ] === listener || list [ i ] . listener === listener ) {
581
+ position = i ;
582
+ break ;
583
+ }
584
+ }
585
+
586
+ if ( position < 0 )
587
+ return this ;
588
+
589
+ if ( position === 0 )
590
+ list . shift ( ) ;
591
+ else {
592
+ if ( spliceOne === undefined )
593
+ spliceOne = require ( 'internal/util' ) . spliceOne ;
594
+ spliceOne ( list , position ) ;
554
595
}
596
+
597
+ if ( list . length === 1 )
598
+ events [ type ] = list [ 0 ] ;
599
+
555
600
if ( events . removeListener !== undefined )
556
601
this . emit ( 'removeListener' , type , listener ) ;
557
602
}
@@ -675,7 +720,19 @@ EventEmitter.prototype.listenerCount = listenerCount;
675
720
* @returns {number }
676
721
*/
677
722
function listenerCount ( type ) {
678
- return this . _events ?. [ type ] ?. length || 0 ;
723
+ const events = this . _events ;
724
+
725
+ if ( events !== undefined ) {
726
+ const evlistener = events [ type ] ;
727
+
728
+ if ( typeof evlistener === 'function' ) {
729
+ return 1 ;
730
+ } else if ( evlistener !== undefined ) {
731
+ return evlistener . length ;
732
+ }
733
+ }
734
+
735
+ return 0 ;
679
736
}
680
737
681
738
/**
0 commit comments