@@ -27,6 +27,7 @@ const {
2727 ArrayPrototypeShift,
2828 ArrayPrototypeSlice,
2929 ArrayPrototypeSplice,
30+ ArrayPrototypeUnshift,
3031 Boolean,
3132 Error,
3233 ErrorCaptureStackTrace,
@@ -42,6 +43,7 @@ const {
4243 Promise,
4344 PromiseReject,
4445 PromiseResolve,
46+ ReflectApply,
4547 ReflectOwnKeys,
4648 String,
4749 StringPrototypeSplit,
@@ -59,6 +61,7 @@ const {
5961 kEnhanceStackBeforeInspector,
6062 codes : {
6163 ERR_INVALID_ARG_TYPE ,
64+ ERR_INVALID_THIS ,
6265 ERR_OUT_OF_RANGE ,
6366 ERR_UNHANDLED_ERROR
6467 } ,
@@ -76,6 +79,122 @@ const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners');
7679const kMaxEventTargetListenersWarned =
7780 Symbol ( 'events.maxEventTargetListenersWarned' ) ;
7881
82+ let EventEmitterAsyncResource ;
83+ // The EventEmitterAsyncResource has to be initialized lazily because event.js
84+ // is loaded so early in the bootstrap process, before async_hooks is available.
85+ //
86+ // This implementation was adapted straight from addaleax's
87+ // eventemitter-asyncresource MIT-licensed userland module.
88+ // https://github.com/addaleax/eventemitter-asyncresource
89+ function lazyEventEmitterAsyncResource ( ) {
90+ if ( EventEmitterAsyncResource === undefined ) {
91+ const {
92+ AsyncResource
93+ } = require ( 'async_hooks' ) ;
94+
95+ const kEventEmitter = Symbol ( 'kEventEmitter' ) ;
96+ const kAsyncResource = Symbol ( 'kAsyncResource' ) ;
97+ class EventEmitterReferencingAsyncResource extends AsyncResource {
98+ /**
99+ * @param {EventEmitter } ee
100+ * @param {string } [type]
101+ * @param {{
102+ * triggerAsyncId?: number,
103+ * requireManualDestroy?: boolean,
104+ * }} [options]
105+ */
106+ constructor ( ee , type , options ) {
107+ super ( type , options ) ;
108+ this [ kEventEmitter ] = ee ;
109+ }
110+
111+ /**
112+ * @type {EventEmitter }
113+ */
114+ get eventEmitter ( ) {
115+ if ( this [ kEventEmitter ] === undefined )
116+ throw new ERR_INVALID_THIS ( 'EventEmitterReferencingAsyncResource' ) ;
117+ return this [ kEventEmitter ] ;
118+ }
119+ }
120+
121+ EventEmitterAsyncResource =
122+ class EventEmitterAsyncResource extends EventEmitter {
123+ /**
124+ * @param {{
125+ * name?: string,
126+ * triggerAsyncId?: number,
127+ * requireManualDestroy?: boolean,
128+ * }} [options]
129+ */
130+ constructor ( options = undefined ) {
131+ let name ;
132+ if ( typeof options === 'string' ) {
133+ name = options ;
134+ options = undefined ;
135+ } else {
136+ name = options ?. name || new . target . name ;
137+ }
138+ super ( options ) ;
139+
140+ this [ kAsyncResource ] =
141+ new EventEmitterReferencingAsyncResource ( this , name , options ) ;
142+ }
143+
144+ /**
145+ * @param {symbol,string } event
146+ * @param {...any } args
147+ * @returns {boolean }
148+ */
149+ emit ( event , ...args ) {
150+ if ( this [ kAsyncResource ] === undefined )
151+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
152+ const { asyncResource } = this ;
153+ ArrayPrototypeUnshift ( args , super . emit , this , event ) ;
154+ return ReflectApply ( asyncResource . runInAsyncScope , asyncResource ,
155+ args ) ;
156+ }
157+
158+ /**
159+ * @returns {void }
160+ */
161+ emitDestroy ( ) {
162+ if ( this [ kAsyncResource ] === undefined )
163+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
164+ this . asyncResource . emitDestroy ( ) ;
165+ }
166+
167+ /**
168+ * @returns {number }
169+ */
170+ asyncId ( ) {
171+ if ( this [ kAsyncResource ] === undefined )
172+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
173+ return this . asyncResource . asyncId ( ) ;
174+ }
175+
176+ /**
177+ * @returns {number }
178+ */
179+ triggerAsyncId ( ) {
180+ if ( this [ kAsyncResource ] === undefined )
181+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
182+ return this . asyncResource . triggerAsyncId ( ) ;
183+ }
184+
185+ /**
186+ * @returns {EventEmitterReferencingAsyncResource }
187+ */
188+ get asyncResource ( ) {
189+ if ( this [ kAsyncResource ] === undefined )
190+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
191+ return this [ kAsyncResource ] ;
192+ }
193+ } ;
194+ }
195+ return EventEmitterAsyncResource ;
196+ }
197+
79198/**
80199 * Creates a new `EventEmitter` instance.
81200 * @param {{ captureRejections?: boolean; } } [opts]
@@ -106,6 +225,13 @@ ObjectDefineProperty(EventEmitter, 'captureRejections', {
106225 enumerable : true
107226} ) ;
108227
228+ ObjectDefineProperty ( EventEmitter , 'EventEmitterAsyncResource' , {
229+ enumerable : true ,
230+ get : lazyEventEmitterAsyncResource ,
231+ set : undefined ,
232+ configurable : true ,
233+ } ) ;
234+
109235EventEmitter . errorMonitor = kErrorMonitor ;
110236
111237// The default for captureRejections is false
0 commit comments