Skip to content

Instantly share code, notes, and snippets.

@cef62
Forked from domenic/event-emitter.js
Created November 21, 2016 13:34
Show Gist options
  • Save cef62/2d5ab9f1062cedf269714b8704d3c393 to your computer and use it in GitHub Desktop.
Save cef62/2d5ab9f1062cedf269714b8704d3c393 to your computer and use it in GitHub Desktop.
Revealing constructor pattern event-emitter
// This event emitter emits events, but reserves the right to publish events to
// for its creator. It uses a WeakMap for true encapsulation.
const eesToEventMaps = new WeakMap();
export default class EventEmitter {
constructor(publisher) {
const eventMap = Object.create(null);
eesToEventMaps.set(this, eventMap);
publisher(makePublish(this));
}
on(eventName, handler) {
const eventMap = eesToEventMaps.get(this);
let handlers = eventMap[eventName];
if (!handlers) {
handlers = eventMap[eventName] = [];
}
handlers.push(handler);
}
off(eventName, handler) {
const eventMap = eesToEventMaps.get(this);
const handlers = eventMap[eventName];
if (!handlers) {
return;
}
const index = handlers.indexOf(handler);
if (index === -1) {
return;
}
handlers.splice(index, -1);
}
}
function makePublish(ee) {
const eventMap = eesToEventMaps.get(ee);
return function (eventName, ...args) {
const handlers = eventMap[eventName];
if (handlers) {
handlers.forEach(h => h(...args));
}
};
}
const myEE = new EventEmitter(publish => {
// Wait for interesting things to happen, then call
// `publish("eventName", ...args)`.
});
passToOtherCode(myEE);
// The other code only gets access to `on` and `off`: it cannot trigger spurious
// events, but only listen for them. This makes it safe to pass `myEE` to
// multiple consumers without worrying about them accidentally stepping on each
// other's toes.
// (Of course, they could intentionally step on each other's toes, e.g. by
// overwriting `on` or `off`. For true security you'll need to deeply-freeze
// `myEE`, and do a few more things, e.g. to protect against plan interference
// attacks. We're not focused on that right now, but instead on the API
// ergonomics.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment