Skip to content

Instantly share code, notes, and snippets.

@xincici
Last active September 25, 2019 06:00
Show Gist options
  • Save xincici/e64d79e0a77c14c90794cb9fb213f9ec to your computer and use it in GitHub Desktop.
Save xincici/e64d79e0a77c14c90794cb9fb213f9ec to your computer and use it in GitHub Desktop.
just one simple implementation of NodeJS EventEmitter module
var assert = require('assert');
var util = require('util');
function on(thisArg, eventName, fn, isOnce, isPrepend) {
assert(eventName && typeof fn === 'function', 'Need eventName and callback function');
if (eventName !== 'newListener' || thisArg.listenerCount('newListener')){
thisArg.emit('newListener', eventName, fn);
}
if (thisArg.fns[eventName]) {
if (thisArg.fns[eventName].length < thisArg.getMaxListeners()) {
thisArg.fns[eventName][isPrepend ? 'unshift' : 'push']({
fn,
isOnce,
});
} else {
throw new TypeError('maxListeners exceed!');
}
} else {
thisArg.fns[eventName] = [{
fn,
isOnce,
}];
}
return thisArg;
}
class Event {
constructor() {
this.fns = {};
}
on(eventName, fn) {
return on(this, eventName, fn);
}
addListener(eventName, fn) {
return on(this, eventName, fn);
}
once(eventName, fn) {
return on(this, eventName, fn, true);
}
prependListener(eventName, fn) {
return on(this, eventName, fn, false, true);
}
prependOnceListener(eventName, fn) {
return on(this, eventName, fn, true, true);
}
emit(eventName, ...args) {
var cbs = this.fns[eventName];
if (cbs && cbs.length) {
cbs.forEach(cb => {
if (cb.isOnce) {
this.removeListener(eventName, cb.fn);
}
cb.fn.apply(this, args);
});
return true;
}
return false;
}
removeListener(eventName, fn) {
var cbs = this.fns[eventName];
if (cbs && cbs.length) {
var index = cbs.findIndex(cb => cb.fn === fn);
index >= 0 && this.fns[eventName].splice(index, 1);
if (this.fns[eventName].length === 0) {
delete this.fns[eventName];
}
this.emit('removeListener', eventName, fn);
}
return this;
}
removeAllListeners(eventName) {
if (!eventName) {
this.fns = {};
return this;
}
var eFns = (this.fns[eventName] || []).map(v => v.fn);
delete this.fns[eventName];
eFns.forEach(fn => {
this.emit('removeListener', eventName, fn);
});
return this;
}
listeners(eventName) {
return (this.fns[eventName] || []).map(v => v.fn);
}
listenerCount(eventName) {
return this.fns[eventName] ? this.fns[eventName].length : 0;
}
eventNames() {
return Object.keys(this.fns);
}
getMaxListeners() {
return this.maxListeners || Event.defaultMaxListeners;
}
setMaxListeners(count) {
this.maxListeners = count;
return this;
}
}
Event.listenerCount = util.deprecate(
(emitter, eventName) => emitter.listenerCount(eventName),
'EventEmitter.listenerCount is depreacated, please use emitter.listenerCount instead'
);
Event.defaultMaxListeners = 10;
Event.EventEmitter = Event;
module.exports = Event;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment