Skip to content

Instantly share code, notes, and snippets.

@intrnl
Last active April 21, 2022 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save intrnl/01235cb6837ac4499d9b484d00f85089 to your computer and use it in GitHub Desktop.
Save intrnl/01235cb6837ac4499d9b484d00f85089 to your computer and use it in GitHub Desktop.
EventEmitter
const assert = (condition, message = 'Assertion failed') => {
if (!condition) {
throw new Error(message);
}
}
export class EventEmitter {
#listeners = Object.create(null);
on (type, listener) {
assert(typeof type === 'string');
assert(typeof listener === 'function');
const listeners = this.#listeners;
let existing = listeners[type];
if (existing === undefined) {
listeners[type] = listener;
}
else if (typeof existing === 'function') {
listeners[type] = [existing, listener];
}
else {
existing.push(listener);
}
return this;
}
once (type, listener) {
assert(typeof type === 'string');
assert(typeof listener === 'function');
let fired = false;
const wrapper = (data) => {
if (fired) {
return;
}
fired = true;
this.off(type, wrapper);
listener(data);
};
wrapper.listener = listener;
return this.on(type, wrapper);
}
off (type, listener) {
assert(typeof type === 'string');
assert(typeof listener === 'function');
const listeners = this.#listeners;
let existing = listeners[type];
if (existing === undefined) {
return this;
}
if (existing === listener || existing.listener === listener) {
delete listeners[type];
return this;
}
if (typeof existing !== 'function') {
const length = existing.length;
const duo = length === 2;
for (let idx = length - 1; idx > -1; idx--) {
const x = existing[idx];
if (x === listener || x.listener === listener) {
if (duo) {
listeners[type] = existing[idx === 0 ? 1 : 0];
break;
}
existing = existing.slice();
listeners[type] = existing;
existing.splice(idx, 1);
break;
}
}
}
return this;
}
emit (type, data) {
assert(typeof type === 'string');
const listeners = this.#listeners;
const existing = listeners[type];
if (existing === undefined) {
return false;
}
if (typeof existing === 'function') {
existing(data);
}
else {
const length = existing.length;
for (let idx = 0; idx < length; idx++) {
const listener = existing[idx];
listener(data);
}
}
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment