1'use strict'; 2 3var spliceOne; 4 5function EventEmitter() { 6 EventEmitter.init.call(this); 7} 8 9EventEmitter.EventEmitter = EventEmitter; 10 11EventEmitter.usingDomains = false; 12 13EventEmitter.prototype._events = undefined; 14EventEmitter.prototype._eventsCount = 0; 15EventEmitter.prototype._maxListeners = undefined; 16 17var defaultMaxListeners = 10; 18 19Object.defineProperty(EventEmitter, 'defaultMaxListeners', { 20 enumerable: true, 21 get: function () { 22 return defaultMaxListeners; 23 }, 24 set: function (arg) { 25 if (typeof arg !== 'number' || arg < 0 || Number.isNaN(arg)) { 26 throw new Error('defaultMaxListeners:a non-negative number'); 27 } 28 defaultMaxListeners = arg; 29 } 30}); 31 32EventEmitter.init = function () { 33 34 if (this._events === undefined || 35 this._events === Object.getPrototypeOf(this)._events) { 36 this._events = Object.create(null); 37 this._eventsCount = 0; 38 } 39 40 this._maxListeners = this._maxListeners || undefined; 41}; 42 43EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { 44 if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) { 45 throw new Error('a non-negative number'); 46 } 47 this._maxListeners = n; 48 var that = this; 49 return that; 50}; 51 52function _getMaxListeners(that) { 53 if (that._maxListeners === undefined) 54 return EventEmitter.defaultMaxListeners; 55 return that._maxListeners; 56} 57 58EventEmitter.prototype.getMaxListeners = function getMaxListeners() { 59 return _getMaxListeners(this); 60}; 61 62function longestSeqContainedIn(a, b) { 63 for (var len = a.length; len >= 3; --len) { 64 for (var i = 0; i < a.length - len; ++i) { 65 for (var j = 0; j < b.length - len; ++j) { 66 var matches = true; 67 for (var k = 0; k < len; ++k) { 68 if (a[i + k] !== b[j + k]) { 69 matches = false; 70 break; 71 } 72 } 73 if (matches) 74 return [len, i, j]; 75 } 76 } 77 } 78 79 return [0, 0, 0]; 80} 81 82function enhanceStackTrace(err, own) { 83 var sep = '\nEmitted \'error\' event at:\n'; 84 85 var errStack = err.stack.split('\n').slice(1); 86 var ownStack = own.stack.split('\n').slice(1); 87 88 var seq = longestSeqContainedIn(ownStack, errStack); 89 if (seq.len > 0) { 90 ownStack.splice(seq.off + 1, seq.len - 1, 91 ' [... lines matching original stack trace ...]'); 92 } 93 err.stack = err.stack + sep + ownStack.join('\n'); 94} 95 96EventEmitter.prototype.emit = function emit(type) { 97 var doError = (type === 'error'); 98 99 var events = this._events; 100 if (events !== undefined) 101 doError = (doError && events.error === undefined); 102 else if (!doError) 103 return false; 104 105 var args = []; 106 for (var i = 1, len = arguments.length; i < len; i++) { 107 args.push(arguments[i]); 108 } 109 if (doError) { 110 var er; 111 if (args.length > 0) 112 er = args[0]; 113 if (er instanceof Error) { 114 throw er; 115 } 116 throw new Error('unhandled error'); 117 } 118 119 var handler = events[type]; 120 121 if (handler === undefined) 122 return false; 123 124 if (typeof handler === 'function') { 125 Function.prototype.apply.call(handler, this, args); 126 } else { 127 var len = handler.length; 128 var listeners = arrayClone(handler, len); 129 for (var i = 0; i < len; ++i) 130 Function.prototype.apply.call(listeners[i], this, args); 131 } 132 133 return true; 134}; 135 136function _addListener(target, type, listener, prepend) { 137 var m; 138 var events; 139 var existing; 140 141 if (typeof listener !== 'function') { 142 throw new Error('addListener invalid arg type: Function'); 143 } 144 145 events = target._events; 146 if (events === undefined) { 147 events = target._events = Object.create(null); 148 target._eventsCount = 0; 149 } else { 150 if (events.newListener !== undefined) { 151 target.emit('newListener', type, 152 listener.listener ? listener.listener : listener); 153 events = target._events; 154 } 155 existing = events[type]; 156 } 157 158 if (existing === undefined) { 159 existing = events[type] = listener; 160 ++target._eventsCount; 161 } else { 162 if (typeof existing === 'function') { 163 existing = events[type] = 164 prepend ? [listener, existing] : [existing, listener]; 165 } else if (prepend) { 166 existing.unshift(listener); 167 } else { 168 existing.push(listener); 169 } 170 } 171 172 return target; 173} 174 175EventEmitter.prototype.addListener = function addListener(type, listener) { 176 return _addListener(this, type, listener, false); 177}; 178 179EventEmitter.prototype.on = EventEmitter.prototype.addListener; 180 181EventEmitter.prototype.prependListener = 182 function prependListener(type, listener) { 183 return _addListener(this, type, listener, true); 184 }; 185 186function onceWrapper() { 187 if (!this.fired) { 188 this.target.removeListener(this.type, this.wrapFn); 189 this.fired = true; 190 Function.prototype.apply.call(this.listener, this.target, arguments); 191 } 192} 193 194function _onceWrap(target, type, listener) { 195 var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; 196 var wrapped = onceWrapper.bind(state); 197 wrapped.listener = listener; 198 state.wrapFn = wrapped; 199 return wrapped; 200} 201 202EventEmitter.prototype.once = function once(type, listener) { 203 if (typeof listener !== 'function') { 204 throw new Error('listener invalid arg type'); 205 } 206 this.on(type, _onceWrap(this, type, listener)); 207 var that = this; 208 return that; 209}; 210 211EventEmitter.prototype.prependOnceListener = 212 function prependOnceListener(type, listener) { 213 if (typeof listener !== 'function') { 214 throw new Error('prependOnceListener invalid arg type'); 215 } 216 this.prependListener(type, _onceWrap(this, type, listener)); 217 var that = this; 218 return that; 219 }; 220 221EventEmitter.prototype.removeListener = 222 function removeListener(type, listener) { 223 var list, events, position, i, originalListener; 224 var that = this; 225 226 if (typeof listener !== 'function') { 227 throw new Error('removeListener invalid arg type'); 228 } 229 230 events = this._events; 231 if (events === undefined) 232 return that; 233 234 list = events[type]; 235 if (list === undefined) 236 return that; 237 238 if (list === listener || list.listener === listener) { 239 if (--this._eventsCount === 0) 240 this._events = Object.create(null); 241 else { 242 delete events[type]; 243 if (events.removeListener) 244 this.emit('removeListener', type, list.listener || listener); 245 } 246 } else if (typeof list !== 'function') { 247 position = -1; 248 249 for (i = list.length - 1; i >= 0; i--) { 250 if (list[i] === listener || list[i].listener === listener) { 251 originalListener = list[i].listener; 252 position = i; 253 break; 254 } 255 } 256 257 if (position < 0) 258 return that; 259 260 if (position === 0) 261 list.shift(); 262 else { 263 if (spliceOne === undefined) 264 spliceOne = require('internal/util').spliceOne; 265 spliceOne(list, position); 266 } 267 268 if (list.length === 1) 269 events[type] = list[0]; 270 271 if (events.removeListener !== undefined) 272 this.emit('removeListener', type, originalListener || listener); 273 } 274 275 return that; 276 }; 277 278EventEmitter.prototype.off = EventEmitter.prototype.removeListener; 279 280EventEmitter.prototype.removeAllListeners = 281 function removeAllListeners(type) { 282 var listeners, events, i; 283 var that = this; 284 285 events = this._events; 286 if (events === undefined) 287 return that; 288 289 if (events.removeListener === undefined) { 290 if (arguments.length === 0) { 291 this._events = Object.create(null); 292 this._eventsCount = 0; 293 } else if (events[type] !== undefined) { 294 if (--this._eventsCount === 0) 295 this._events = Object.create(null); 296 else 297 delete events[type]; 298 } 299 return that; 300 } 301 302 if (arguments.length === 0) { 303 var keys = Object.keys(events); 304 var key; 305 for (i = 0; i < keys.length; ++i) { 306 key = keys[i]; 307 if (key === 'removeListener') continue; 308 this.removeAllListeners(key); 309 } 310 this.removeAllListeners('removeListener'); 311 this._events = Object.create(null); 312 this._eventsCount = 0; 313 return that; 314 } 315 316 listeners = events[type]; 317 318 if (typeof listeners === 'function') { 319 this.removeListener(type, listeners); 320 } else if (listeners !== undefined) { 321 for (i = listeners.length - 1; i >= 0; i--) { 322 this.removeListener(type, listeners[i]); 323 } 324 } 325 326 return that; 327 }; 328 329function _listeners(target, type, unwrap) { 330 var events = target._events; 331 332 if (events === undefined) 333 return []; 334 335 var evlistener = events[type]; 336 if (evlistener === undefined) 337 return []; 338 339 if (typeof evlistener === 'function') 340 return unwrap ? [evlistener.listener || evlistener] : [evlistener]; 341 342 return unwrap ? 343 unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); 344} 345 346EventEmitter.prototype.listeners = function listeners(type) { 347 return _listeners(this, type, true); 348}; 349 350EventEmitter.prototype.rawListeners = function rawListeners(type) { 351 return _listeners(this, type, false); 352}; 353 354EventEmitter.listenerCount = function (emitter, type) { 355 if (typeof emitter.listenerCount === 'function') { 356 return emitter.listenerCount(type); 357 } else { 358 return listenerCount.call(emitter, type); 359 } 360}; 361 362EventEmitter.prototype.listenerCount = listenerCount; 363function listenerCount(type) { 364 var events = this._events; 365 366 if (events !== undefined) { 367 var evlistener = events[type]; 368 369 if (typeof evlistener === 'function') { 370 return 1; 371 } else if (evlistener !== undefined) { 372 return evlistener.length; 373 } 374 } 375 376 return 0; 377} 378 379EventEmitter.prototype.eventNames = function eventNames() { 380 return this._eventsCount > 0 ? Function.prototype.apply.call(this._events) : []; 381}; 382 383function arrayClone(arr, n) { 384 var copy = new Array(n); 385 for (var i = 0; i < n; ++i) 386 copy[i] = arr[i]; 387 return copy; 388} 389 390function unwrapListeners(arr) { 391 var ret = new Array(arr.length); 392 for (var i = 0; i < ret.length; ++i) { 393 ret[i] = arr[i].listener || arr[i]; 394 } 395 return ret; 396} 397 398 399module.exports = EventEmitter; 400