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 throw Error('Uncaught, unspecified "error" event.');
148 handler = events[type];
153 if (domain && this !== process) {
155 needDomainExit = true;
158 var isFn = typeof handler === 'function';
159 len = arguments.length;
163 emitNone(handler, isFn, this);
166 emitOne(handler, isFn, this, arguments[1]);
169 emitTwo(handler, isFn, this, arguments[1], arguments[2]);
172 emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
176 args = new Array(len - 1);
177 for (i = 1; i < len; i++)
178 args[i - 1] = arguments[i];
179 emitMany(handler, isFn, this, args);
188 EventEmitter.prototype.addListener = function addListener(type, listener) {
193 if (typeof listener !== 'function')
194 throw new TypeError('listener must be a function');
196 events = this._events;
198 events = this._events = {};
199 this._eventsCount = 0;
201 // To avoid recursion in the case that type === "newListener"! Before
202 // adding it to the listeners, first emit "newListener".
203 if (events.newListener) {
204 this.emit('newListener', type,
205 listener.listener ? listener.listener : listener);
207 // Re-assign `events` because a newListener handler could have caused the
208 // this._events to be assigned to a new object
209 events = this._events;
211 existing = events[type];
215 // Optimize the case of one listener. Don't need the extra array object.
216 existing = events[type] = listener;
219 if (typeof existing === 'function') {
220 // Adding the second element, need to change to array.
221 existing = events[type] = [existing, listener];
223 // If we've already got an array, just append.
224 existing.push(listener);
227 // Check for listener leak
228 if (!existing.warned) {
229 m = $getMaxListeners(this);
230 if (m && m > 0 && existing.length > m) {
231 existing.warned = true;
232 console.error('(node) warning: possible EventEmitter memory ' +
233 'leak detected. %d %s listeners added. ' +
234 'Use emitter.setMaxListeners() to increase limit.',
235 existing.length, type);
244 EventEmitter.prototype.on = EventEmitter.prototype.addListener;
246 EventEmitter.prototype.once = function once(type, listener) {
247 if (typeof listener !== 'function')
248 throw new TypeError('listener must be a function');
253 this.removeListener(type, g);
257 listener.apply(this, arguments);
261 g.listener = listener;
267 // emits a 'removeListener' event iff the listener was removed
268 EventEmitter.prototype.removeListener =
269 function removeListener(type, listener) {
270 var list, events, position, i;
272 if (typeof listener !== 'function')
273 throw new TypeError('listener must be a function');
275 events = this._events;
283 if (list === listener || (list.listener && list.listener === listener)) {
284 if (--this._eventsCount === 0)
288 if (events.removeListener)
289 this.emit('removeListener', type, listener);
291 } else if (typeof list !== 'function') {
294 for (i = list.length; i-- > 0;) {
295 if (list[i] === listener ||
296 (list[i].listener && list[i].listener === listener)) {
305 if (list.length === 1) {
307 if (--this._eventsCount === 0) {
313 spliceOne(list, position);
316 if (events.removeListener)
317 this.emit('removeListener', type, listener);
323 EventEmitter.prototype.removeAllListeners =
324 function removeAllListeners(type) {
325 var listeners, events;
327 events = this._events;
331 // not listening for removeListener, no need to emit
332 if (!events.removeListener) {
333 if (arguments.length === 0) {
335 this._eventsCount = 0;
336 } else if (events[type]) {
337 if (--this._eventsCount === 0)
345 // emit removeListener for all listeners on all events
346 if (arguments.length === 0) {
347 var keys = Object.keys(events);
348 for (var i = 0, key; i < keys.length; ++i) {
350 if (key === 'removeListener') continue;
351 this.removeAllListeners(key);
353 this.removeAllListeners('removeListener');
355 this._eventsCount = 0;
359 listeners = events[type];
361 if (typeof listeners === 'function') {
362 this.removeListener(type, listeners);
363 } else if (listeners) {
366 this.removeListener(type, listeners[listeners.length - 1]);
367 } while (listeners[0]);
373 EventEmitter.prototype.listeners = function listeners(type) {
376 var events = this._events;
381 evlistener = events[type];
384 else if (typeof evlistener === 'function')
387 ret = arrayClone(evlistener);
393 EventEmitter.listenerCount = function(emitter, type) {
396 var events = emitter._events;
399 evlistener = events[type];
400 if (typeof evlistener === 'function')
403 ret = evlistener.length;
409 // About 1.5x faster than the two-arg version of Array#splice().
410 function spliceOne(list, index) {
411 for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
416 function arrayClone(arr, len) {
418 if (len === undefined)
423 ret = new Array(len);
424 for (var i = 0; i < len; i += 1)