5 function EventEmitter() {
6 EventEmitter.init.call(this);
8 module.exports = EventEmitter;
10 // Backwards-compat with node 0.10.x
11 EventEmitter.EventEmitter = EventEmitter;
13 EventEmitter.usingDomains = false;
15 EventEmitter.prototype.domain = undefined;
16 EventEmitter.prototype._events = undefined;
17 EventEmitter.prototype._maxListeners = undefined;
19 // By default EventEmitters will print a warning if more than 10 listeners are
20 // added to it. This is a useful default which helps finding memory leaks.
21 EventEmitter.defaultMaxListeners = 10;
23 EventEmitter.init = function() {
25 if (EventEmitter.usingDomains) {
26 // if there is an active domain, then attach to it.
27 domain = domain || require('domain');
28 if (domain.active && !(this instanceof domain.Domain)) {
29 this.domain = domain.active;
33 if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
35 this._eventsCount = 0;
38 this._maxListeners = this._maxListeners || undefined;
41 // Obviously not all Emitters should be limited to 10. This function allows
42 // that to be increased. Set to zero for unlimited.
43 EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
44 if (typeof n !== 'number' || n < 0 || isNaN(n))
45 throw new TypeError('n must be a positive number');
46 this._maxListeners = n;
50 function $getMaxListeners(that) {
51 if (that._maxListeners === undefined)
52 return EventEmitter.defaultMaxListeners;
53 return that._maxListeners;
56 EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
57 return $getMaxListeners(this);
60 // These standalone emit* functions are used to optimize calling of event
61 // handlers for fast cases because emit() itself often has a variable number of
62 // arguments and can be deoptimized because of that. These functions always have
63 // the same number of arguments and thus do not get deoptimized, so the code
64 // inside them can execute faster.
65 function emitNone(handler, isFn, self) {
69 var len = handler.length;
70 var listeners = arrayClone(handler, len);
71 for (var i = 0; i < len; ++i)
72 listeners[i].call(self);
75 function emitOne(handler, isFn, self, arg1) {
77 handler.call(self, arg1);
79 var len = handler.length;
80 var listeners = arrayClone(handler, len);
81 for (var i = 0; i < len; ++i)
82 listeners[i].call(self, arg1);
85 function emitTwo(handler, isFn, self, arg1, arg2) {
87 handler.call(self, arg1, arg2);
89 var len = handler.length;
90 var listeners = arrayClone(handler, len);
91 for (var i = 0; i < len; ++i)
92 listeners[i].call(self, arg1, arg2);
95 function emitThree(handler, isFn, self, arg1, arg2, arg3) {
97 handler.call(self, arg1, arg2, arg3);
99 var len = handler.length;
100 var listeners = arrayClone(handler, len);
101 for (var i = 0; i < len; ++i)
102 listeners[i].call(self, arg1, arg2, arg3);
106 function emitMany(handler, isFn, self, args) {
108 handler.apply(self, args);
110 var len = handler.length;
111 var listeners = arrayClone(handler, len);
112 for (var i = 0; i < len; ++i)
113 listeners[i].apply(self, args);
117 EventEmitter.prototype.emit = function emit(type) {
118 var er, handler, len, args, i, events, domain;
119 var needDomainExit = false;
120 var doError = (type === 'error');
122 events = this._events;
124 doError = (doError && events.error == null);
128 domain = this.domain;
130 // If there is no 'error' event listener then throw.
135 er = new Error('Uncaught, unspecified "error" event.');
136 er.domainEmitter = this;
138 er.domainThrown = false;
139 domain.emit('error', er);
140 } else if (er instanceof Error) {
141 throw er; // Unhandled 'error' event
143 // At least give some kind of context to the user
144 var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
151 handler = events[type];
156 if (domain && this !== process) {
158 needDomainExit = true;
161 var isFn = typeof handler === 'function';
162 len = arguments.length;
166 emitNone(handler, isFn, this);
169 emitOne(handler, isFn, this, arguments[1]);
172 emitTwo(handler, isFn, this, arguments[1], arguments[2]);
175 emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
179 args = new Array(len - 1);
180 for (i = 1; i < len; i++)
181 args[i - 1] = arguments[i];
182 emitMany(handler, isFn, this, args);
191 EventEmitter.prototype.addListener = function addListener(type, listener) {
196 if (typeof listener !== 'function')
197 throw new TypeError('listener must be a function');
199 events = this._events;
201 events = this._events = {};
202 this._eventsCount = 0;
204 // To avoid recursion in the case that type === "newListener"! Before
205 // adding it to the listeners, first emit "newListener".
206 if (events.newListener) {
207 this.emit('newListener', type,
208 listener.listener ? listener.listener : listener);
210 // Re-assign `events` because a newListener handler could have caused the
211 // this._events to be assigned to a new object
212 events = this._events;
214 existing = events[type];
218 // Optimize the case of one listener. Don't need the extra array object.
219 existing = events[type] = listener;
222 if (typeof existing === 'function') {
223 // Adding the second element, need to change to array.
224 existing = events[type] = [existing, listener];
226 // If we've already got an array, just append.
227 existing.push(listener);
230 // Check for listener leak
231 if (!existing.warned) {
232 m = $getMaxListeners(this);
233 if (m && m > 0 && existing.length > m) {
234 existing.warned = true;
235 console.error('(node) warning: possible EventEmitter memory ' +
236 'leak detected. %d %s listeners added. ' +
237 'Use emitter.setMaxListeners() to increase limit.',
238 existing.length, type);
247 EventEmitter.prototype.on = EventEmitter.prototype.addListener;
249 EventEmitter.prototype.once = function once(type, listener) {
250 if (typeof listener !== 'function')
251 throw new TypeError('listener must be a function');
256 this.removeListener(type, g);
260 listener.apply(this, arguments);
264 g.listener = listener;
270 // emits a 'removeListener' event iff the listener was removed
271 EventEmitter.prototype.removeListener =
272 function removeListener(type, listener) {
273 var list, events, position, i;
275 if (typeof listener !== 'function')
276 throw new TypeError('listener must be a function');
278 events = this._events;
286 if (list === listener || (list.listener && list.listener === listener)) {
287 if (--this._eventsCount === 0)
291 if (events.removeListener)
292 this.emit('removeListener', type, listener);
294 } else if (typeof list !== 'function') {
297 for (i = list.length; i-- > 0;) {
298 if (list[i] === listener ||
299 (list[i].listener && list[i].listener === listener)) {
308 if (list.length === 1) {
310 if (--this._eventsCount === 0) {
317 spliceOne(list, position);
320 if (events.removeListener)
321 this.emit('removeListener', type, listener);
327 EventEmitter.prototype.removeAllListeners =
328 function removeAllListeners(type) {
329 var listeners, events;
331 events = this._events;
335 // not listening for removeListener, no need to emit
336 if (!events.removeListener) {
337 if (arguments.length === 0) {
339 this._eventsCount = 0;
340 } else if (events[type]) {
341 if (--this._eventsCount === 0)
349 // emit removeListener for all listeners on all events
350 if (arguments.length === 0) {
351 var keys = Object.keys(events);
352 for (var i = 0, key; i < keys.length; ++i) {
354 if (key === 'removeListener') continue;
355 this.removeAllListeners(key);
357 this.removeAllListeners('removeListener');
359 this._eventsCount = 0;
363 listeners = events[type];
365 if (typeof listeners === 'function') {
366 this.removeListener(type, listeners);
367 } else if (listeners) {
370 this.removeListener(type, listeners[listeners.length - 1]);
371 } while (listeners[0]);
377 EventEmitter.prototype.listeners = function listeners(type) {
380 var events = this._events;
385 evlistener = events[type];
388 else if (typeof evlistener === 'function')
391 ret = arrayClone(evlistener, evlistener.length);
397 EventEmitter.listenerCount = function(emitter, type) {
398 if (typeof emitter.listenerCount === 'function') {
399 return emitter.listenerCount(type);
401 return listenerCount.call(emitter, type);
405 EventEmitter.prototype.listenerCount = listenerCount;
406 function listenerCount(type) {
407 const events = this._events;
410 const evlistener = events[type];
412 if (typeof evlistener === 'function') {
414 } else if (evlistener) {
415 return evlistener.length;
422 // About 1.5x faster than the two-arg version of Array#splice().
423 function spliceOne(list, index) {
424 for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
429 function arrayClone(arr, i) {
430 var copy = new Array(i);