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