function EventEmitter() {
/**
* 賦予 this 個別屬性
* 壓過 prototype
*
* domain
* _events
* _eventsCount
* _maxListeners
*
*/
EventEmitter.init.call(this);
}
/**
* 類別方法
*/
(function(fn) {
fn.usingDomains = false;
fn.defaultMaxListeners = 10;
fn.init = function() {
this.domain = null;
if (EventEmitter.usingDomains) {
// if there is an active domain, then attach to it.
domain = domain || require('domain');
if (domain.active && !(this instanceof domain.Domain)) {
this.domain = domain.active;
}
}
if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
this._events = new EventHandlers();
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
};
fn.listenerCount = function(emitter, type) {
if (typeof emitter.listenerCount === 'function') {
return emitter.listenerCount(type);
} else {
return listenerCount.call(emitter, type);
}
};
})(EventEmitter);
(function() {
this.domain;
this._events;
this._maxListeners;
this.setMaxListeners = function(n) {
if (typeof n !== 'number' || n < 0 || isNaN(n))
throw new TypeError('"n" argument must be a positive number');
this._maxListeners = n;
return this;
};
this.getMaxListeners = function() {
return $getMaxListeners(this);
}
this.emit = function(type) {
var er, handler, len, args, i, events, domain;
var needDomainExit = false;
var doError = (type === 'error');
events = this._events;
if (events)
doError = (doError && events.error == null);
else if (!doError)
return false;
domain = this.domain;
// If there is no 'error' event listener then throw.
if (doError) {
er = arguments[1];
if (domain) {
if (!er)
er = new Error('Uncaught, unspecified "error" event');
er.domainEmitter = this;
er.domain = domain;
er.domainThrown = false;
domain.emit('error', er);
} else if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
return false;
}
handler = events[type];
if (!handler)
return false;
if (domain && this !== process) {
domain.enter();
needDomainExit = true;
}
var isFn = typeof handler === 'function';
len = arguments.length;
switch (len) {
// fast cases
case 1:
emitNone(handler, isFn, this);
break;
case 2:
emitOne(handler, isFn, this, arguments[1]);
break;
case 3:
emitTwo(handler, isFn, this, arguments[1], arguments[2]);
break;
case 4:
emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
break;
// slower
default:
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
emitMany(handler, isFn, this, args);
}
if (needDomainExit) {
domain.exit();
}
return true;
}
this.addListener = function(type, listener) {
return _addListener(this, type, listener, false);
};
this.prependListener = function(type, listener) {
return _addListener(this, type, listener, true);
};
this.once = function(type, listener) {
if (typeof listener !== 'function') {
throw new TypeError('"listener" argument must be a function');
}
this.on(type, _onceWrap(this, type, listener));
return this;
};
this.prependOnceListener = function(type, listener) {
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
this.prependListener(type, _onceWrap(this, type, listener));
return this;
};
function removeListener(type, listener) {
var list, events, position, i, originalListener;
if (typeof listener !== 'function') {
throw new TypeError('"listener" argument must be a function');
}
// this._events = {}
events = this._events;
if (!events) {
return this;
}
// [fn, fn]
list = events[type];
if (!list) {
return this;
}
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else {
delete events[type];
if (events.removeListener)
this.emit('removeListener', type, list.listener || listener);
}
} else if (typeof list !== 'function') {
// list 是陣列
position = -1;
// core
for (i = list.length; i-- > 0;) {
if (list[i] === listener || list[i].listener === listener) {
originalListener = list[i].listener;
position = i;
break;
}
}
if (position < 0) {
return this;
}
if (list.length === 1) {
list[0] = undefined;
if (--this._eventsCount === 0) {
this._events = new EventHandlers();
return this;
} else {
delete events[type];
}
} else {
spliceOne(list, position);
}
if (events.removeListener)
this.emit('removeListener', type, originalListener || listener);
}
return this;
};
this.removeAllListeners = function(type) {
var listeners, events;
events = this._events;
if (!events) {
return this;
}
// not listening for removeListener, no need to emit
if (!events.removeListener) {
if (arguments.length === 0) {
this._events = new EventHandlers();
this._eventsCount = 0;
} else if (events[type]) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else
delete events[type];
}
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
var keys = Object.keys(events);
for (var i = 0, key; i < keys.length; ++i) {
key = keys[i];
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = new EventHandlers();
this._eventsCount = 0;
return this;
}
listeners = events[type];
if (typeof listeners === 'function') {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
do {
this.removeListener(type, listeners[listeners.length - 1]);
} while (listeners[0]);
}
return this;
};
this.listeners = function(type) {
var evlistener;
var ret;
var events = this._events;
if (!events) {
ret = [];
} else {
evlistener = events[type];
if (!evlistener) {
ret = [];
} else if (typeof evlistener === 'function') {
ret = [evlistener];
} else
ret = arrayClone(evlistener, evlistener.length);
}
return ret;
};
this.listenerCount = function(type) {
const events = this._events;
if (events) {
const evlistener = events[type];
if (typeof evlistener === 'function') {
return 1;
} else if (evlistener) {
return evlistener.length;
}
}
return 0;
};
this.eventNames = function() {
return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
};
}).call(EventEmitter.prototype);