@@ -32,8 +32,13 @@ const kEvents = Symbol('kEvents');
3232const kStop = Symbol ( 'kStop' ) ;
3333const kTarget = Symbol ( 'kTarget' ) ;
3434
35+ const kHybridDispatch = Symbol . for ( 'nodejs.internal.kHybridDispatch' ) ;
36+ const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
3537const kNewListener = Symbol ( 'kNewListener' ) ;
3638const kRemoveListener = Symbol ( 'kRemoveListener' ) ;
39+ const kIsNodeStyleListener = Symbol ( 'kIsNodeStyleListener' ) ;
40+ const kMaxListeners = Symbol ( 'kMaxListeners' ) ;
41+ const kMaxListenersWarned = Symbol ( 'kMaxListenersWarned' ) ;
3742
3843// Lazy load perf_hooks to avoid the additional overhead on startup
3944let perf_hooks ;
@@ -161,7 +166,7 @@ Object.defineProperty(Event.prototype, SymbolToStringTag, {
161166// the linked list makes dispatching faster, even if adding/removing is
162167// slower.
163168class Listener {
164- constructor ( previous , listener , once , capture , passive ) {
169+ constructor ( previous , listener , once , capture , passive , isNodeStyleListener ) {
165170 this . next = undefined ;
166171 if ( previous !== undefined )
167172 previous . next = this ;
@@ -170,6 +175,7 @@ class Listener {
170175 this . once = once ;
171176 this . capture = capture ;
172177 this . passive = passive ;
178+ this . isNodeStyleListener = isNodeStyleListener ;
173179
174180 this . callback =
175181 typeof listener === 'function' ?
@@ -189,13 +195,17 @@ class Listener {
189195 }
190196}
191197
198+ function initEventTarget ( self ) {
199+ self [ kEvents ] = new Map ( ) ;
200+ }
201+
192202class EventTarget {
193203 // Used in checking whether an object is an EventTarget. This is a well-known
194204 // symbol as EventTarget may be used cross-realm. See discussion in #33661.
195205 static [ kIsEventTarget ] = true ;
196206
197207 constructor ( ) {
198- this [ kEvents ] = new Map ( ) ;
208+ initEventTarget ( this ) ;
199209 }
200210
201211 [ kNewListener ] ( size , type , listener , once , capture , passive ) { }
@@ -210,7 +220,8 @@ class EventTarget {
210220 const {
211221 once,
212222 capture,
213- passive
223+ passive,
224+ isNodeStyleListener
214225 } = validateEventListenerOptions ( options ) ;
215226
216227 if ( ! shouldAddListener ( listener ) ) {
@@ -232,7 +243,7 @@ class EventTarget {
232243 if ( root === undefined ) {
233244 root = { size : 1 , next : undefined } ;
234245 // This is the first handler in our linked list.
235- new Listener ( root , listener , once , capture , passive ) ;
246+ new Listener ( root , listener , once , capture , passive , isNodeStyleListener ) ;
236247 this [ kNewListener ] ( root . size , type , listener , once , capture , passive ) ;
237248 this [ kEvents ] . set ( type , root ) ;
238249 return ;
@@ -251,7 +262,8 @@ class EventTarget {
251262 return ;
252263 }
253264
254- new Listener ( previous , listener , once , capture , passive ) ;
265+ new Listener ( previous , listener , once , capture , passive ,
266+ isNodeStyleListener ) ;
255267 root . size ++ ;
256268 this [ kNewListener ] ( root . size , type , listener , once , capture , passive ) ;
257269 }
@@ -294,39 +306,61 @@ class EventTarget {
294306 if ( event [ kTarget ] !== null )
295307 throw new ERR_EVENT_RECURSION ( event . type ) ;
296308
297- const root = this [ kEvents ] . get ( event . type ) ;
309+ this [ kHybridDispatch ] ( event , event . type , event ) ;
310+
311+ return event . defaultPrevented !== true ;
312+ }
313+
314+ [ kHybridDispatch ] ( nodeValue , type , event ) {
315+ const createEvent = ( ) => {
316+ if ( event === undefined ) {
317+ event = this [ kCreateEvent ] ( nodeValue , type ) ;
318+ event [ kTarget ] = this ;
319+ }
320+ return event ;
321+ } ;
322+
323+ const root = this [ kEvents ] . get ( type ) ;
298324 if ( root === undefined || root . next === undefined )
299325 return true ;
300326
301- event [ kTarget ] = this ;
327+ if ( event !== undefined )
328+ event [ kTarget ] = this ;
302329
303330 let handler = root . next ;
304331 let next ;
305332
306333 while ( handler !== undefined &&
307- ( handler . passive || event [ kStop ] !== true ) ) {
334+ ( handler . passive || event ?. [ kStop ] !== true ) ) {
308335 // Cache the next item in case this iteration removes the current one
309336 next = handler . next ;
310337
311338 if ( handler . once ) {
312339 handler . remove ( ) ;
313340 root . size -- ;
341+ const { listener, capture } = handler ;
342+ this [ kRemoveListener ] ( root . size , type , listener , capture ) ;
314343 }
315344
316345 try {
317- const result = handler . callback . call ( this , event ) ;
346+ let arg ;
347+ if ( handler . isNodeStyleListener ) {
348+ arg = nodeValue ;
349+ } else {
350+ arg = createEvent ( ) ;
351+ }
352+ const result = handler . callback . call ( this , arg ) ;
318353 if ( result !== undefined && result !== null )
319- addCatch ( this , result , event ) ;
354+ addCatch ( this , result , createEvent ( ) ) ;
320355 } catch ( err ) {
321- emitUnhandledRejectionOrErr ( this , err , event ) ;
356+ emitUnhandledRejectionOrErr ( this , err , createEvent ( ) ) ;
322357 }
323358
324359 handler = next ;
325360 }
326361
327- event [ kTarget ] = undefined ;
328-
329- return event . defaultPrevented !== true ;
362+ if ( event !== undefined )
363+ event [ kTarget ] = undefined ;
330364 }
331365
332366 [ customInspectSymbol ] ( depth , options ) {
@@ -354,15 +388,19 @@ Object.defineProperty(EventTarget.prototype, SymbolToStringTag, {
354388 value : 'EventTarget' ,
355389} ) ;
356390
357- const kMaxListeners = Symbol ( 'maxListeners' ) ;
358- const kMaxListenersWarned = Symbol ( 'maxListenersWarned' ) ;
391+ function initNodeEventTarget ( self ) {
392+ initEventTarget ( self ) ;
393+ // eslint-disable-next-line no-use-before-define
394+ self [ kMaxListeners ] = NodeEventTarget . defaultMaxListeners ;
395+ self [ kMaxListenersWarned ] = false ;
396+ }
397+
359398class NodeEventTarget extends EventTarget {
360399 static defaultMaxListeners = 10 ;
361400
362401 constructor ( ) {
363402 super ( ) ;
364- this [ kMaxListeners ] = NodeEventTarget . defaultMaxListeners ;
365- this [ kMaxListenersWarned ] = false ;
403+ initNodeEventTarget ( this ) ;
366404 }
367405
368406 [ kNewListener ] ( size , type , listener , once , capture , passive ) {
@@ -414,17 +452,18 @@ class NodeEventTarget extends EventTarget {
414452 }
415453
416454 on ( type , listener ) {
417- this . addEventListener ( type , listener ) ;
455+ this . addEventListener ( type , listener , { [ kIsNodeStyleListener ] : true } ) ;
418456 return this ;
419457 }
420458
421459 addListener ( type , listener ) {
422- this . addEventListener ( type , listener ) ;
460+ this . addEventListener ( type , listener , { [ kIsNodeStyleListener ] : true } ) ;
423461 return this ;
424462 }
425463
426464 once ( type , listener ) {
427- this . addEventListener ( type , listener , { once : true } ) ;
465+ this . addEventListener ( type , listener ,
466+ { once : true , [ kIsNodeStyleListener ] : true } ) ;
428467 return this ;
429468 }
430469
@@ -474,6 +513,7 @@ function validateEventListenerOptions(options) {
474513 once : Boolean ( options . once ) ,
475514 capture : Boolean ( options . capture ) ,
476515 passive : Boolean ( options . passive ) ,
516+ isNodeStyleListener : Boolean ( options [ kIsNodeStyleListener ] )
477517 } ;
478518}
479519
@@ -524,4 +564,9 @@ module.exports = {
524564 EventTarget,
525565 NodeEventTarget,
526566 defineEventHandler,
567+ initEventTarget,
568+ initNodeEventTarget,
569+ kCreateEvent,
570+ kNewListener,
571+ kRemoveListener,
527572} ;
0 commit comments