23
23
24
24
const {
25
25
Array,
26
+ Boolean,
26
27
Error,
27
28
MathMin,
28
29
NumberIsNaN,
@@ -33,7 +34,10 @@ const {
33
34
Promise,
34
35
ReflectApply,
35
36
ReflectOwnKeys,
37
+ Symbol,
38
+ SymbolFor,
36
39
} = primordials ;
40
+ const kRejection = SymbolFor ( 'nodejs.rejection' ) ;
37
41
38
42
let spliceOne ;
39
43
@@ -51,8 +55,10 @@ const {
51
55
inspect
52
56
} = require ( 'internal/util/inspect' ) ;
53
57
54
- function EventEmitter ( ) {
55
- EventEmitter . init . call ( this ) ;
58
+ const kCapture = Symbol ( 'kCapture' ) ;
59
+
60
+ function EventEmitter ( opts ) {
61
+ EventEmitter . init . call ( this , opts ) ;
56
62
}
57
63
module . exports = EventEmitter ;
58
64
module . exports . once = once ;
@@ -62,6 +68,29 @@ EventEmitter.EventEmitter = EventEmitter;
62
68
63
69
EventEmitter . usingDomains = false ;
64
70
71
+ EventEmitter . captureRejectionSymbol = kRejection ;
72
+ ObjectDefineProperty ( EventEmitter , 'captureRejections' , {
73
+ get ( ) {
74
+ return EventEmitter . prototype [ kCapture ] ;
75
+ } ,
76
+ set ( value ) {
77
+ if ( typeof value !== 'boolean' ) {
78
+ throw new ERR_INVALID_ARG_TYPE ( 'EventEmitter.captureRejections' ,
79
+ 'boolean' , value ) ;
80
+ }
81
+
82
+ EventEmitter . prototype [ kCapture ] = value ;
83
+ } ,
84
+ enumerable : true
85
+ } ) ;
86
+
87
+ // The default for captureRejections is false
88
+ ObjectDefineProperty ( EventEmitter . prototype , kCapture , {
89
+ value : false ,
90
+ writable : true ,
91
+ enumerable : false
92
+ } ) ;
93
+
65
94
EventEmitter . prototype . _events = undefined ;
66
95
EventEmitter . prototype . _eventsCount = 0 ;
67
96
EventEmitter . prototype . _maxListeners = undefined ;
@@ -91,7 +120,7 @@ ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
91
120
}
92
121
} ) ;
93
122
94
- EventEmitter . init = function ( ) {
123
+ EventEmitter . init = function ( opts ) {
95
124
96
125
if ( this . _events === undefined ||
97
126
this . _events === ObjectGetPrototypeOf ( this ) . _events ) {
@@ -100,8 +129,64 @@ EventEmitter.init = function() {
100
129
}
101
130
102
131
this . _maxListeners = this . _maxListeners || undefined ;
132
+
133
+
134
+ if ( opts && opts . captureRejections ) {
135
+ if ( typeof opts . captureRejections !== 'boolean' ) {
136
+ throw new ERR_INVALID_ARG_TYPE ( 'options.captureRejections' ,
137
+ 'boolean' , opts . captureRejections ) ;
138
+ }
139
+ this [ kCapture ] = Boolean ( opts . captureRejections ) ;
140
+ } else {
141
+ // Assigning it directly a prototype lookup, as it slighly expensive
142
+ // and it sits in a very sensitive hot path.
143
+ this [ kCapture ] = EventEmitter . prototype [ kCapture ] ;
144
+ }
103
145
} ;
104
146
147
+ function addCatch ( that , promise , type , args ) {
148
+ if ( ! that [ kCapture ] ) {
149
+ return ;
150
+ }
151
+
152
+ // Handle Promises/A+ spec, then could be a getter
153
+ // that throws on second use.
154
+ try {
155
+ const then = promise . then ;
156
+
157
+ if ( typeof then === 'function' ) {
158
+ then . call ( promise , undefined , function ( err ) {
159
+ // The callback is called with nextTick to avoid a follow-up
160
+ // rejection from this promise.
161
+ process . nextTick ( emitUnhandledRejectionOrErr , that , err , type , args ) ;
162
+ } ) ;
163
+ }
164
+ } catch ( err ) {
165
+ that . emit ( 'error' , err ) ;
166
+ }
167
+ }
168
+
169
+ function emitUnhandledRejectionOrErr ( ee , err , type , args ) {
170
+ if ( typeof ee [ kRejection ] === 'function' ) {
171
+ ee [ kRejection ] ( err , type , ...args ) ;
172
+ } else {
173
+ // We have to disable the capture rejections mechanism, otherwise
174
+ // we might end up in an infinite loop.
175
+ const prev = ee [ kCapture ] ;
176
+
177
+ // If the error handler throws, it is not catcheable and it
178
+ // will end up in 'uncaughtException'. We restore the previous
179
+ // value of kCapture in case the uncaughtException is present
180
+ // and the exception is handled.
181
+ try {
182
+ ee [ kCapture ] = false ;
183
+ ee . emit ( 'error' , err ) ;
184
+ } finally {
185
+ ee [ kCapture ] = prev ;
186
+ }
187
+ }
188
+ }
189
+
105
190
// Obviously not all Emitters should be limited to 10. This function allows
106
191
// that to be increased. Set to zero for unlimited.
107
192
EventEmitter . prototype . setMaxListeners = function setMaxListeners ( n ) {
@@ -218,12 +303,29 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
218
303
return false ;
219
304
220
305
if ( typeof handler === 'function' ) {
221
- ReflectApply ( handler , this , args ) ;
306
+ const result = ReflectApply ( handler , this , args ) ;
307
+
308
+ // We check if result is undefined first because that
309
+ // is the most common case so we do not pay any perf
310
+ // penalty
311
+ if ( result !== undefined && result !== null ) {
312
+ addCatch ( this , result , type , args ) ;
313
+ }
222
314
} else {
223
315
const len = handler . length ;
224
316
const listeners = arrayClone ( handler , len ) ;
225
- for ( let i = 0 ; i < len ; ++ i )
226
- ReflectApply ( listeners [ i ] , this , args ) ;
317
+ for ( var i = 0 ; i < len ; ++ i ) {
318
+ const result = ReflectApply ( listeners [ i ] , this , args ) ;
319
+
320
+ // We check if result is undefined first because that
321
+ // is the most common case so we do not pay any perf
322
+ // penalty.
323
+ // This code is duplicated because extracting it away
324
+ // would make it non-inlineable.
325
+ if ( result !== undefined && result !== null ) {
326
+ addCatch ( this , result , type , args ) ;
327
+ }
328
+ }
227
329
}
228
330
229
331
return true ;
0 commit comments