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