@@ -50,15 +50,38 @@ var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
5050 return value !== value ;
5151}
5252
53- function EventEmitter ( ) {
54- EventEmitter . init . call ( this ) ;
53+ var kCapture = typeof Symbol === 'function' ? Symbol ( 'kCapture' ) : '_fakeSymbol_kCapture' ;
54+ var kRejection = typeof Symbol === 'function' && typeof Symbol . for === 'function' ? Symbol . for ( 'nodejs.rejection' ) : '_fakeSymbol_nodejs.rejection' ;
55+
56+ function EventEmitter ( opts ) {
57+ EventEmitter . init . call ( this , opts ) ;
5558}
5659module . exports = EventEmitter ;
5760module . exports . once = once ;
5861
5962// Backwards-compat with node 0.10.x
6063EventEmitter . EventEmitter = EventEmitter ;
6164
65+ EventEmitter . captureRejectionSymbol = kRejection ;
66+ Object . defineProperty ( EventEmitter , 'captureRejections' , {
67+ get : function ( ) {
68+ return EventEmitter . prototype [ kCapture ] ;
69+ } ,
70+ set : function ( value ) {
71+ if ( typeof value !== 'boolean' ) {
72+ throw new TypeError ( 'The "EventEmitter.captureRejections" argument must be of type boolean. Received type ' + typeof value ) ;
73+ }
74+ EventEmitter . prototype [ kCapture ] = value ;
75+ } ,
76+ enumerable : true
77+ } ) ;
78+
79+ Object . defineProperty ( EventEmitter . prototype , kCapture , {
80+ value : false ,
81+ writable : true ,
82+ enumerable : false
83+ } ) ;
84+
6285EventEmitter . prototype . _events = undefined ;
6386EventEmitter . prototype . _eventsCount = 0 ;
6487EventEmitter . prototype . _maxListeners = undefined ;
@@ -86,7 +109,7 @@ Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
86109 }
87110} ) ;
88111
89- EventEmitter . init = function ( ) {
112+ EventEmitter . init = function init ( opts ) {
90113
91114 if ( this . _events === undefined ||
92115 this . _events === Object . getPrototypeOf ( this ) . _events ) {
@@ -95,8 +118,61 @@ EventEmitter.init = function() {
95118 }
96119
97120 this . _maxListeners = this . _maxListeners || undefined ;
121+
122+ if ( opts && opts . captureRejections ) {
123+ if ( typeof opts . captureRejections !== 'boolean' ) {
124+ throw new TypeError ( 'The "options.captureRejections" argument must be of type boolean. Received type ' + typeof opts . captureRejections ) ;
125+ }
126+ this [ kCapture ] = Boolean ( opts . captureRejections ) ;
127+ } else {
128+ this [ kCapture ] = EventEmitter . prototype [ kCapture ] ;
129+ }
98130} ;
99131
132+ var ProcessNextTick = typeof queueMicrotask === 'function'
133+ ? queueMicrotask
134+ : typeof setImmediate === 'function'
135+ ? setImmediate
136+ : setTimeout ;
137+
138+ function addCatch ( that , promise , type , args ) {
139+ if ( ! that [ kCapture ] ) {
140+ return ;
141+ }
142+
143+ // Handle Promises/A+ spec, then could be a getter
144+ // that throws on second use.
145+ try {
146+ var then = promise . then ;
147+ if ( typeof then === 'function' ) {
148+ then . call ( promise , undefined , function ( err ) {
149+ ProcessNextTick ( function ( ) {
150+ emitUnhandledRejectionOrErr ( that , err , type , args ) ;
151+ } ) ;
152+ } ) ;
153+ }
154+ } catch ( err ) {
155+ that . emit ( 'error' , err ) ;
156+ }
157+ }
158+
159+ function emitUnhandledRejectionOrErr ( ee , err , type , args ) {
160+ if ( typeof ee [ kRejection ] === 'function' ) {
161+ ee [ kRejection ] . apply ( ee , [ err , type ] . concat ( args ) ) ;
162+ } else {
163+ // We have to disable the capture rejections mechanism, otherwise
164+ // we might end up in an infinite loop.
165+ var prev = ee [ kCapture ] ;
166+
167+ try {
168+ ee [ kCapture ] = false ;
169+ ee . emit ( 'error' , err ) ;
170+ } finally {
171+ ee [ kCapture ] = prev ;
172+ }
173+ }
174+ }
175+
100176// Obviously not all Emitters should be limited to 10. This function allows
101177// that to be increased. Set to zero for unlimited.
102178EventEmitter . prototype . setMaxListeners = function setMaxListeners ( n ) {
@@ -150,12 +226,29 @@ EventEmitter.prototype.emit = function emit(type) {
150226 return false ;
151227
152228 if ( typeof handler === 'function' ) {
153- ReflectApply ( handler , this , args ) ;
229+ var result = ReflectApply ( handler , this , args ) ;
230+
231+ // We check if result is undefined first because that
232+ // is the most common case so we do not pay any perf
233+ // penalty
234+ if ( result !== undefined && result !== null ) {
235+ addCatch ( this , result , type , args ) ;
236+ }
154237 } else {
155238 var len = handler . length ;
156239 var listeners = arrayClone ( handler , len ) ;
157- for ( var i = 0 ; i < len ; ++ i )
158- ReflectApply ( listeners [ i ] , this , args ) ;
240+ for ( var i = 0 ; i < len ; ++ i ) {
241+ var result = ReflectApply ( listeners [ i ] , this , args ) ;
242+
243+ // We check if result is undefined first because that
244+ // is the most common case so we do not pay any perf
245+ // penalty.
246+ // This code is duplicated because extracting it away
247+ // would make it non-inlineable.
248+ if ( result !== undefined && result !== null ) {
249+ addCatch ( this , result , type , args ) ;
250+ }
251+ }
159252 }
160253
161254 return true ;
0 commit comments