@@ -31,8 +31,13 @@ const kEvents = Symbol('kEvents');
31
31
const kStop = Symbol ( 'kStop' ) ;
32
32
const kTarget = Symbol ( 'kTarget' ) ;
33
33
34
+ const kHybridDispatch = Symbol . for ( 'nodejs.internal.kHybridDispatch' ) ;
35
+ const kCreateEvent = Symbol ( 'kCreateEvent' ) ;
34
36
const kNewListener = Symbol ( 'kNewListener' ) ;
35
37
const kRemoveListener = Symbol ( 'kRemoveListener' ) ;
38
+ const kIsNodeStyleListener = Symbol ( 'kIsNodeStyleListener' ) ;
39
+ const kMaxListeners = Symbol ( 'kMaxListeners' ) ;
40
+ const kMaxListenersWarned = Symbol ( 'kMaxListenersWarned' ) ;
36
41
37
42
// Lazy load perf_hooks to avoid the additional overhead on startup
38
43
let perf_hooks ;
@@ -157,7 +162,7 @@ Object.defineProperty(Event.prototype, SymbolToStringTag, {
157
162
// the linked list makes dispatching faster, even if adding/removing is
158
163
// slower.
159
164
class Listener {
160
- constructor ( previous , listener , once , capture , passive ) {
165
+ constructor ( previous , listener , once , capture , passive , isNodeStyleListener ) {
161
166
this . next = undefined ;
162
167
if ( previous !== undefined )
163
168
previous . next = this ;
@@ -166,6 +171,7 @@ class Listener {
166
171
this . once = once ;
167
172
this . capture = capture ;
168
173
this . passive = passive ;
174
+ this . isNodeStyleListener = isNodeStyleListener ;
169
175
170
176
this . callback =
171
177
typeof listener === 'function' ?
@@ -185,13 +191,17 @@ class Listener {
185
191
}
186
192
}
187
193
194
+ function initEventTarget ( self ) {
195
+ self [ kEvents ] = new Map ( ) ;
196
+ }
197
+
188
198
class EventTarget {
189
199
// Used in checking whether an object is an EventTarget. This is a well-known
190
200
// symbol as EventTarget may be used cross-realm. See discussion in #33661.
191
201
static [ kIsEventTarget ] = true ;
192
202
193
203
constructor ( ) {
194
- this [ kEvents ] = new Map ( ) ;
204
+ initEventTarget ( this ) ;
195
205
}
196
206
197
207
[ kNewListener ] ( size , type , listener , once , capture , passive ) { }
@@ -206,7 +216,8 @@ class EventTarget {
206
216
const {
207
217
once,
208
218
capture,
209
- passive
219
+ passive,
220
+ isNodeStyleListener
210
221
} = validateEventListenerOptions ( options ) ;
211
222
212
223
if ( ! shouldAddListener ( listener ) ) {
@@ -228,7 +239,7 @@ class EventTarget {
228
239
if ( root === undefined ) {
229
240
root = { size : 1 , next : undefined } ;
230
241
// This is the first handler in our linked list.
231
- new Listener ( root , listener , once , capture , passive ) ;
242
+ new Listener ( root , listener , once , capture , passive , isNodeStyleListener ) ;
232
243
this [ kNewListener ] ( root . size , type , listener , once , capture , passive ) ;
233
244
this [ kEvents ] . set ( type , root ) ;
234
245
return ;
@@ -247,7 +258,8 @@ class EventTarget {
247
258
return ;
248
259
}
249
260
250
- new Listener ( previous , listener , once , capture , passive ) ;
261
+ new Listener ( previous , listener , once , capture , passive ,
262
+ isNodeStyleListener ) ;
251
263
root . size ++ ;
252
264
this [ kNewListener ] ( root . size , type , listener , once , capture , passive ) ;
253
265
}
@@ -290,39 +302,61 @@ class EventTarget {
290
302
if ( event [ kTarget ] !== null )
291
303
throw new ERR_EVENT_RECURSION ( event . type ) ;
292
304
293
- const root = this [ kEvents ] . get ( event . type ) ;
305
+ this [ kHybridDispatch ] ( event , event . type , event ) ;
306
+
307
+ return event . defaultPrevented !== true ;
308
+ }
309
+
310
+ [ kHybridDispatch ] ( nodeValue , type , event ) {
311
+ const createEvent = ( ) => {
312
+ if ( event === undefined ) {
313
+ event = this [ kCreateEvent ] ( nodeValue , type ) ;
314
+ event [ kTarget ] = this ;
315
+ }
316
+ return event ;
317
+ } ;
318
+
319
+ const root = this [ kEvents ] . get ( type ) ;
294
320
if ( root === undefined || root . next === undefined )
295
321
return true ;
296
322
297
- event [ kTarget ] = this ;
323
+ if ( event !== undefined )
324
+ event [ kTarget ] = this ;
298
325
299
326
let handler = root . next ;
300
327
let next ;
301
328
302
329
while ( handler !== undefined &&
303
- ( handler . passive || event [ kStop ] !== true ) ) {
330
+ ( handler . passive || event ?. [ kStop ] !== true ) ) {
304
331
// Cache the next item in case this iteration removes the current one
305
332
next = handler . next ;
306
333
307
334
if ( handler . once ) {
308
335
handler . remove ( ) ;
309
336
root . size -- ;
337
+ const { listener, capture } = handler ;
338
+ this [ kRemoveListener ] ( root . size , type , listener , capture ) ;
310
339
}
311
340
312
341
try {
313
- const result = handler . callback . call ( this , event ) ;
342
+ let arg ;
343
+ if ( handler . isNodeStyleListener ) {
344
+ arg = nodeValue ;
345
+ } else {
346
+ arg = createEvent ( ) ;
347
+ }
348
+ const result = handler . callback . call ( this , arg ) ;
314
349
if ( result !== undefined && result !== null )
315
- addCatch ( this , result , event ) ;
350
+ addCatch ( this , result , createEvent ( ) ) ;
316
351
} catch ( err ) {
317
- emitUnhandledRejectionOrErr ( this , err , event ) ;
352
+ emitUnhandledRejectionOrErr ( this , err , createEvent ( ) ) ;
318
353
}
319
354
320
355
handler = next ;
321
356
}
322
357
323
- event [ kTarget ] = undefined ;
324
-
325
- return event . defaultPrevented !== true ;
358
+ if ( event !== undefined )
359
+ event [ kTarget ] = undefined ;
326
360
}
327
361
328
362
[ customInspectSymbol ] ( depth , options ) {
@@ -350,15 +384,19 @@ Object.defineProperty(EventTarget.prototype, SymbolToStringTag, {
350
384
value : 'EventTarget' ,
351
385
} ) ;
352
386
353
- const kMaxListeners = Symbol ( 'maxListeners' ) ;
354
- const kMaxListenersWarned = Symbol ( 'maxListenersWarned' ) ;
387
+ function initNodeEventTarget ( self ) {
388
+ initEventTarget ( self ) ;
389
+ // eslint-disable-next-line no-use-before-define
390
+ self [ kMaxListeners ] = NodeEventTarget . defaultMaxListeners ;
391
+ self [ kMaxListenersWarned ] = false ;
392
+ }
393
+
355
394
class NodeEventTarget extends EventTarget {
356
395
static defaultMaxListeners = 10 ;
357
396
358
397
constructor ( ) {
359
398
super ( ) ;
360
- this [ kMaxListeners ] = NodeEventTarget . defaultMaxListeners ;
361
- this [ kMaxListenersWarned ] = false ;
399
+ initNodeEventTarget ( this ) ;
362
400
}
363
401
364
402
[ kNewListener ] ( size , type , listener , once , capture , passive ) {
@@ -410,17 +448,18 @@ class NodeEventTarget extends EventTarget {
410
448
}
411
449
412
450
on ( type , listener ) {
413
- this . addEventListener ( type , listener ) ;
451
+ this . addEventListener ( type , listener , { [ kIsNodeStyleListener ] : true } ) ;
414
452
return this ;
415
453
}
416
454
417
455
addListener ( type , listener ) {
418
- this . addEventListener ( type , listener ) ;
456
+ this . addEventListener ( type , listener , { [ kIsNodeStyleListener ] : true } ) ;
419
457
return this ;
420
458
}
421
459
422
460
once ( type , listener ) {
423
- this . addEventListener ( type , listener , { once : true } ) ;
461
+ this . addEventListener ( type , listener ,
462
+ { once : true , [ kIsNodeStyleListener ] : true } ) ;
424
463
return this ;
425
464
}
426
465
@@ -470,6 +509,7 @@ function validateEventListenerOptions(options) {
470
509
once : Boolean ( options . once ) ,
471
510
capture : Boolean ( options . capture ) ,
472
511
passive : Boolean ( options . passive ) ,
512
+ isNodeStyleListener : Boolean ( options [ kIsNodeStyleListener ] )
473
513
} ;
474
514
}
475
515
@@ -520,4 +560,9 @@ module.exports = {
520
560
EventTarget,
521
561
NodeEventTarget,
522
562
defineEventHandler,
563
+ initEventTarget,
564
+ initNodeEventTarget,
565
+ kCreateEvent,
566
+ kNewListener,
567
+ kRemoveListener,
523
568
} ;
0 commit comments