2323
2424const {
2525 Array,
26+ Boolean,
2627 Error,
2728 MathMin,
2829 NumberIsNaN,
@@ -33,7 +34,10 @@ const {
3334 Promise,
3435 ReflectApply,
3536 ReflectOwnKeys,
37+ Symbol,
38+ SymbolFor,
3639} = primordials ;
40+ const kRejection = SymbolFor ( 'nodejs.rejection' ) ;
3741
3842let spliceOne ;
3943
@@ -51,8 +55,10 @@ const {
5155 inspect
5256} = require ( 'internal/util/inspect' ) ;
5357
54- function EventEmitter ( ) {
55- EventEmitter . init . call ( this ) ;
58+ const kCapture = Symbol ( 'kCapture' ) ;
59+
60+ function EventEmitter ( opts ) {
61+ EventEmitter . init . call ( this , opts ) ;
5662}
5763module . exports = EventEmitter ;
5864module . exports . once = once ;
@@ -62,6 +68,29 @@ EventEmitter.EventEmitter = EventEmitter;
6268
6369EventEmitter . usingDomains = false ;
6470
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+
6594EventEmitter . prototype . _events = undefined ;
6695EventEmitter . prototype . _eventsCount = 0 ;
6796EventEmitter . prototype . _maxListeners = undefined ;
@@ -91,7 +120,7 @@ ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
91120 }
92121} ) ;
93122
94- EventEmitter . init = function ( ) {
123+ EventEmitter . init = function ( opts ) {
95124
96125 if ( this . _events === undefined ||
97126 this . _events === ObjectGetPrototypeOf ( this ) . _events ) {
@@ -100,8 +129,64 @@ EventEmitter.init = function() {
100129 }
101130
102131 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+ }
103145} ;
104146
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+
105190// Obviously not all Emitters should be limited to 10. This function allows
106191// that to be increased. Set to zero for unlimited.
107192EventEmitter . prototype . setMaxListeners = function setMaxListeners ( n ) {
@@ -218,12 +303,29 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
218303 return false ;
219304
220305 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+ }
222314 } else {
223315 const len = handler . length ;
224316 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+ }
227329 }
228330
229331 return true ;
0 commit comments