@@ -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 } ,
@@ -68,6 +71,7 @@ const {
6871 validateAbortSignal,
6972 validateBoolean,
7073 validateFunction,
74+ validateString,
7175} = require ( 'internal/validators' ) ;
7276
7377const kCapture = Symbol ( 'kCapture' ) ;
@@ -76,6 +80,125 @@ const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners');
7680const kMaxEventTargetListenersWarned =
7781 Symbol ( 'events.maxEventTargetListenersWarned' ) ;
7882
83+ let EventEmitterAsyncResource ;
84+ // The EventEmitterAsyncResource has to be initialized lazily because event.js
85+ // is loaded so early in the bootstrap process, before async_hooks is available.
86+ //
87+ // This implementation was adapted straight from addaleax's
88+ // eventemitter-asyncresource MIT-licensed userland module.
89+ // https://github.com/addaleax/eventemitter-asyncresource
90+ function lazyEventEmitterAsyncResource ( ) {
91+ if ( EventEmitterAsyncResource === undefined ) {
92+ const {
93+ AsyncResource
94+ } = require ( 'async_hooks' ) ;
95+
96+ const kEventEmitter = Symbol ( 'kEventEmitter' ) ;
97+ const kAsyncResource = Symbol ( 'kAsyncResource' ) ;
98+ class EventEmitterReferencingAsyncResource extends AsyncResource {
99+ /**
100+ * @param {EventEmitter } ee
101+ * @param {string } [type]
102+ * @param {{
103+ * triggerAsyncId?: number,
104+ * requireManualDestroy?: boolean,
105+ * }} [options]
106+ */
107+ constructor ( ee , type , options ) {
108+ super ( type , options ) ;
109+ this [ kEventEmitter ] = ee ;
110+ }
111+
112+ /**
113+ * @type {EventEmitter }
114+ */
115+ get eventEmitter ( ) {
116+ if ( this [ kEventEmitter ] === undefined )
117+ throw new ERR_INVALID_THIS ( 'EventEmitterReferencingAsyncResource' ) ;
118+ return this [ kEventEmitter ] ;
119+ }
120+ }
121+
122+ EventEmitterAsyncResource =
123+ class EventEmitterAsyncResource extends EventEmitter {
124+ /**
125+ * @param {{
126+ * name?: string,
127+ * triggerAsyncId?: number,
128+ * requireManualDestroy?: boolean,
129+ * }} [options]
130+ */
131+ constructor ( options = undefined ) {
132+ let name ;
133+ if ( typeof options === 'string' ) {
134+ name = options ;
135+ options = undefined ;
136+ } else {
137+ if ( new . target === EventEmitterAsyncResource ) {
138+ validateString ( options ?. name , 'options.name' ) ;
139+ }
140+ name = options ?. name || new . target . name ;
141+ }
142+ super ( options ) ;
143+
144+ this [ kAsyncResource ] =
145+ new EventEmitterReferencingAsyncResource ( this , name , options ) ;
146+ }
147+
148+ /**
149+ * @param {symbol,string } event
150+ * @param {...any } args
151+ * @returns {boolean }
152+ */
153+ emit ( event , ...args ) {
154+ if ( this [ kAsyncResource ] === undefined )
155+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
156+ const { asyncResource } = this ;
157+ ArrayPrototypeUnshift ( args , super . emit , this , event ) ;
158+ return ReflectApply ( asyncResource . runInAsyncScope , asyncResource ,
159+ args ) ;
160+ }
161+
162+ /**
163+ * @returns {void }
164+ */
165+ emitDestroy ( ) {
166+ if ( this [ kAsyncResource ] === undefined )
167+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
168+ this . asyncResource . emitDestroy ( ) ;
169+ }
170+
171+ /**
172+ * @type {number }
173+ */
174+ get asyncId ( ) {
175+ if ( this [ kAsyncResource ] === undefined )
176+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
177+ return this . asyncResource . asyncId ( ) ;
178+ }
179+
180+ /**
181+ * @type {number }
182+ */
183+ get triggerAsyncId ( ) {
184+ if ( this [ kAsyncResource ] === undefined )
185+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
186+ return this . asyncResource . triggerAsyncId ( ) ;
187+ }
188+
189+ /**
190+ * @type {EventEmitterReferencingAsyncResource }
191+ */
192+ get asyncResource ( ) {
193+ if ( this [ kAsyncResource ] === undefined )
194+ throw new ERR_INVALID_THIS ( 'EventEmitterAsyncResource' ) ;
195+ return this [ kAsyncResource ] ;
196+ }
197+ } ;
198+ }
199+ return EventEmitterAsyncResource ;
200+ }
201+
79202/**
80203 * Creates a new `EventEmitter` instance.
81204 * @param {{ captureRejections?: boolean; } } [opts]
@@ -106,6 +229,13 @@ ObjectDefineProperty(EventEmitter, 'captureRejections', {
106229 enumerable : true
107230} ) ;
108231
232+ ObjectDefineProperty ( EventEmitter , 'EventEmitterAsyncResource' , {
233+ enumerable : true ,
234+ get : lazyEventEmitterAsyncResource ,
235+ set : undefined ,
236+ configurable : true ,
237+ } ) ;
238+
109239EventEmitter . errorMonitor = kErrorMonitor ;
110240
111241// The default for captureRejections is false
0 commit comments