1
- export class EventEmitter <
2
- Events extends { [ name : string ] : ( ...args : any [ ] ) => any }
3
- > {
4
- private readonly _events : {
5
- [ name in keyof Events ] ?: Array < Events [ name ] >
6
- } = { }
1
+ type ListenerFunction = {
2
+ listener ?: Function ;
3
+ } & Function
7
4
8
- on ( event : keyof Events , listener : Events [ typeof event ] ) : ( ) => void {
9
- if ( ! this . _hasEvent ( event ) ) this . _events [ event ] = [ ]
5
+ export class EventEmitter {
6
+ static defaultMaxListeners : number = 10 ;
7
+ maxListeners : number | undefined ;
8
+ events : Map < string | symbol , Function [ ] > ;
10
9
11
- this . _events [ event ] . push ( listener )
12
- return ( ) => this . removeListener ( event , listener )
10
+ constructor ( ) {
11
+ this . events = new Map ( ) ;
13
12
}
14
13
15
- removeListener ( event : keyof Events , listener : Events [ typeof event ] ) : void {
16
- if ( ! this . _hasEvent ( event ) ) return
14
+ _addListener (
15
+ eventName : string | symbol ,
16
+ listener : Function ,
17
+ prepend : boolean
18
+ ) : this {
19
+ this . emit ( "newListener" , eventName , listener ) ;
20
+ if ( this . events . has ( eventName ) ) {
21
+ const listeners = this . events . get ( eventName ) as Function [ ] ;
22
+ if ( prepend ) {
23
+ listeners . unshift ( listener ) ;
24
+ } else {
25
+ listeners . push ( listener ) ;
26
+ }
27
+ } else {
28
+ this . events . set ( eventName , [ listener ] ) ;
29
+ }
30
+ const max = this . getMaxListeners ( ) ;
31
+ if ( max > 0 && this . listenerCount ( eventName ) > max ) {
32
+ const warning = new Error (
33
+ `Possible EventEmitter memory leak detected.
34
+ ${ this . listenerCount ( eventName ) } ${ eventName . toString ( ) } listeners.
35
+ Use emitter.setMaxListeners() to increase limit`
36
+ ) ;
37
+ warning . name = "MaxListenersExceededWarning" ;
38
+ console . warn ( warning ) ;
39
+ }
17
40
18
- const index = this . _events [ event ] . indexOf ( listener )
19
- if ( ~ index ) this . _events [ event ] . splice ( index , 1 )
41
+ return this ;
20
42
}
21
43
22
- emit ( event : keyof Events , ...args : Parameters < Events [ typeof event ] > ) : void {
23
- if ( ! this . _hasEvent ( event ) ) return
44
+ addListener ( eventName : string | symbol , listener : Function ) : this {
45
+ return this . _addListener ( eventName , listener , false ) ;
46
+ }
47
+
48
+ emit ( eventName : string | symbol , ...args : any [ ] ) : boolean {
49
+ if ( this . events . has ( eventName ) ) {
50
+ const listeners = ( this . events . get ( eventName ) as Function [ ] ) . slice ( ) ; // We copy with slice() so array is not mutated during emit
51
+ for ( const listener of listeners ) {
52
+ try {
53
+ listener . apply ( this , args ) ;
54
+ } catch ( err ) {
55
+ this . emit ( "error" , err ) ;
56
+ }
57
+ }
58
+ return true ;
59
+ } else if ( eventName === "error" ) {
60
+ const errMsg = args . length > 0 ? args [ 0 ] : Error ( "Unhandled error." ) ;
61
+ throw errMsg ;
62
+ }
63
+ return false ;
64
+ }
65
+
66
+ eventNames ( ) : [ string | symbol ] {
67
+ return Array . from ( this . events . keys ( ) ) as [ string | symbol ] ;
68
+ }
69
+
70
+ getMaxListeners ( ) : number {
71
+ return this . maxListeners || EventEmitter . defaultMaxListeners ;
72
+ }
73
+
74
+ listenerCount ( eventName : string | symbol ) : number {
75
+ if ( this . events . has ( eventName ) ) {
76
+ return ( this . events . get ( eventName ) as Function [ ] ) . length ;
77
+ } else {
78
+ return 0 ;
79
+ }
80
+ }
81
+
82
+ _listeners (
83
+ target : EventEmitter ,
84
+ eventName : string | symbol ,
85
+ unwrap : boolean
86
+ ) : Function [ ] {
87
+ if ( ! target . events . has ( eventName ) ) {
88
+ return [ ] ;
89
+ }
90
+
91
+ const eventListeners : ListenerFunction [ ] = target . events . get (
92
+ eventName
93
+ ) as Function [ ] ;
94
+
95
+ return unwrap
96
+ ? this . unwrapListeners ( eventListeners )
97
+ : eventListeners . slice ( 0 ) ;
98
+ }
99
+
100
+ unwrapListeners ( arr : ListenerFunction [ ] ) : Function [ ] {
101
+ let unwrappedListeners : Function [ ] = new Array ( arr . length ) as Function [ ] ;
102
+ for ( let i = 0 ; i < arr . length ; i ++ ) {
103
+ unwrappedListeners [ i ] = arr [ i ] [ "listener" ] || arr [ i ] ;
104
+ }
105
+ return unwrappedListeners ;
106
+ }
107
+
108
+ listeners ( eventName : string | symbol ) : Function [ ] {
109
+ return this . _listeners ( this , eventName , true ) ;
110
+ }
111
+
112
+ rawListeners ( eventName : string | symbol ) : Function [ ] {
113
+ return this . _listeners ( this , eventName , false ) ;
114
+ }
115
+
116
+ off ( eventName : string | symbol , listener : Function ) : this {
117
+ return this . removeListener ( eventName , listener ) ;
118
+ }
119
+
120
+ on ( eventName : string | symbol , listener : Function ) : this {
121
+ return this . addListener ( eventName , listener ) ;
122
+ }
123
+
124
+ once ( eventName : string | symbol , listener : Function ) : this {
125
+ const wrapped : Function = this . onceWrap ( eventName , listener ) ;
126
+ this . on ( eventName , wrapped ) ;
127
+ return this ;
128
+ }
129
+
130
+ // Wrapped function that calls EventEmitter.removeListener(eventName, self) on execution.
131
+ onceWrap ( eventName : string | symbol , listener : Function ) : Function {
132
+ const wrapper : ListenerFunction = function (
133
+ this : {
134
+ eventName : string | symbol ;
135
+ listener : Function ;
136
+ rawListener : Function ;
137
+ context : EventEmitter ;
138
+ } ,
139
+ ...args : any [ ] // eslint-disable-line @typescript-eslint/no-explicit-any
140
+ ) : void {
141
+ this . context . removeListener ( this . eventName , this . rawListener ) ;
142
+ this . listener . apply ( this . context , args ) ;
143
+ } ;
144
+ const wrapperContext = {
145
+ eventName : eventName ,
146
+ listener : listener ,
147
+ rawListener : wrapper ,
148
+ context : this
149
+ } ;
150
+ const wrapped = wrapper . bind ( wrapperContext ) ;
151
+ wrapperContext . rawListener = wrapped ;
152
+ wrapped . listener = listener ;
153
+ return wrapped ;
154
+ }
155
+
156
+ prependListener ( eventName : string | symbol , listener : Function ) : this {
157
+ return this . _addListener ( eventName , listener , true ) ;
158
+ }
159
+
160
+ prependOnceListener (
161
+ eventName : string | symbol ,
162
+ listener : Function
163
+ ) : this {
164
+ const wrapped : Function = this . onceWrap ( eventName , listener ) ;
165
+ this . prependListener ( eventName , wrapped ) ;
166
+ return this ;
167
+ }
168
+
169
+ removeAllListeners ( eventName ?: string | symbol ) : this {
170
+ if ( this . events === undefined ) {
171
+ return this ;
172
+ }
173
+
174
+ if ( eventName && this . events . has ( eventName ) ) {
175
+ const listeners = ( this . events . get ( eventName ) as Function [ ] ) . slice ( ) ; // Create a copy; We use it AFTER it's deleted.
176
+ this . events . delete ( eventName ) ;
177
+ for ( const listener of listeners ) {
178
+ this . emit ( "removeListener" , eventName , listener ) ;
179
+ }
180
+ } else {
181
+ const eventList : [ string | symbol ] = this . eventNames ( ) ;
182
+ eventList . map ( ( value : string | symbol ) => {
183
+ this . removeAllListeners ( value ) ;
184
+ } ) ;
185
+ }
186
+
187
+ return this ;
188
+ }
24
189
25
- this . _events [ event ] . map ( ( listener ) => listener . apply ( this , args ) )
190
+ removeListener ( eventName : string | symbol , listener : Function ) : this {
191
+ if ( this . events . has ( eventName ) ) {
192
+ const arr : Function [ ] = this . events . get ( eventName ) as Function [ ] ;
193
+ if ( arr . indexOf ( listener ) !== - 1 ) {
194
+ arr . splice ( arr . indexOf ( listener ) , 1 ) ;
195
+ this . emit ( "removeListener" , eventName , listener ) ;
196
+ if ( arr . length === 0 ) {
197
+ this . events . delete ( eventName ) ;
198
+ }
199
+ }
200
+ }
201
+ return this ;
26
202
}
27
203
28
- private _hasEvent ( event : keyof Events ) {
29
- return Array . isArray ( this . _events [ event ] )
204
+ setMaxListeners ( n : number ) : this {
205
+ this . maxListeners = n ;
206
+ return this ;
30
207
}
31
- }
208
+ }
0 commit comments