Skip to content

Instantly share code, notes, and snippets.

@rafpro
Forked from mudge/eventemitter.js
Last active January 9, 2019 17:37
Show Gist options
  • Save rafpro/9c3d5807d4a830e9284ed24c0a2af1bc to your computer and use it in GitHub Desktop.
Save rafpro/9c3d5807d4a830e9284ed24c0a2af1bc to your computer and use it in GitHub Desktop.
A very simple EventEmitter in pure JavaScript (suitable for both node.js and browsers).
class EventEmitter{
constructor(){
this.events = {};
}
_getEventListByName(eventName){
if(typeof this.events[eventName] === 'undefined'){
this.events[eventName] = new Set();
}
return this.events[eventName]
}
on(eventName, fn){
this._getEventListByName(eventName).add(fn);
}
once(eventName, fn){
const self = this;
const onceFn = function(...args){
self.removeListener(eventName, onceFn);
fn.apply(self, args);
};
this.on(eventName, onceFn);
}
emit(eventName, ...args){
this._getEventListByName(eventName).forEach(function(fn){
fn.apply(this,args);
}.bind(this));
}
removeListener(eventName, fn){
this._getEventListByName(eventName).delete(fn);
}
}
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (typeof this.events[event] !== 'object') {
this.events[event] = [];
}
this.events[event].push(listener);
return () => this.removeListener(event, listener);
}
removeListener(event, listener) {
if (typeof this.events[event] === 'object') {
const idx = this.events[event].indexOf(listener);
if (idx > -1) {
this.events[event].splice(idx, 1);
}
}
}
emit(event, ...args) {
if (typeof this.events[event] === 'object') {
this.events[event].forEach(listener => listener.apply(this, args));
}
}
once(event, listener) {
const remove = this.on(event, (...args) => {
remove();
listener.apply(this, args);
});
}
};
type Listener = (...args: any[]) => void;
interface IEvents { [event: string]: Listener[]; }
export class EventEmitter {
private readonly events: IEvents = {};
public on(event: string, listener: Listener): () => void {
if (typeof this.events[event] !== "object") {
this.events[event] = [];
}
this.events[event].push(listener);
return () => this.removeListener(event, listener);
}
public removeListener(event: string, listener: Listener): void {
if (typeof this.events[event] !== "object") {
return;
}
const idx: number = this.events[event].indexOf(listener);
if (idx > -1) {
this.events[event].splice(idx, 1);
}
}
public removeAllListeners(): void {
Object.keys(this.events).forEach((event: string) =>
this.events[event].splice(0, this.events[event].length),
);
}
public emit(event: string, ...args: any[]): void {
if (typeof this.events[event] !== "object") {
return;
}
[...this.events[event]].forEach((listener) => listener.apply(this, args));
}
public once(event: string, listener: Listener): () => void {
const remove: (() => void) = this.on(event, (...args: any[]) => {
remove();
listener.apply(this, args);
});
return remove;
}
}
/* Polyfill indexOf. */
var indexOf;
if (typeof Array.prototype.indexOf === 'function') {
indexOf = function (haystack, needle) {
return haystack.indexOf(needle);
};
} else {
indexOf = function (haystack, needle) {
var i = 0, length = haystack.length, idx = -1, found = false;
while (i < length && !found) {
if (haystack[i] === needle) {
idx = i;
found = true;
}
i++;
}
return idx;
};
};
/* Polyfill EventEmitter. */
var EventEmitter = function () {
this.events = {};
};
EventEmitter.prototype.on = function (event, listener) {
if (typeof this.events[event] !== 'object') {
this.events[event] = [];
}
this.events[event].push(listener);
};
EventEmitter.prototype.removeListener = function (event, listener) {
var idx;
if (typeof this.events[event] === 'object') {
idx = indexOf(this.events[event], listener);
if (idx > -1) {
this.events[event].splice(idx, 1);
}
}
};
EventEmitter.prototype.emit = function (event) {
var i, listeners, length, args = [].slice.call(arguments, 1);
if (typeof this.events[event] === 'object') {
listeners = this.events[event].slice();
length = listeners.length;
for (i = 0; i < length; i++) {
listeners[i].apply(this, args);
}
}
};
EventEmitter.prototype.once = function (event, listener) {
this.on(event, function g () {
this.removeListener(event, g);
listener.apply(this, arguments);
});
};
type Listener = (...args: any[]) => void
type Events = { [event: string]: Listener[] };
export class MyEventEmitter {
private readonly events: Events = {};
constructor() {
}
public on(event: string, listener: Listener): () => void {
if(typeof this.events[event] !== 'object') this.events[event] = [];
this.events[event].push(listener);
return () => this.removeListener(event, listener);
}
public removeListener(event: string, listener: Listener): void {
if(typeof this.events[event] !== 'object') return;
const idx: number = this.events[event].indexOf(listener);
if(idx > -1) this.events[event].splice(idx, 1);
}
public removeAllListeners(): void {
Object.keys(this.events).forEach((event: string) =>
this.events[event].splice(0, this.events[event].length)
);
}
public emit(event: string, ...args: any[]): void {
if(typeof this.events[event] !== 'object') return;
this.events[event].forEach(listener => listener.apply(this, args));
}
public once(event: string, listener: Listener): void {
const remove: (() => void) = this.on(event, (...args: any[]) => {
remove();
listener.apply(this, args);
});
}
}
const eventify = (self) => {
self.events = {}
self.on = function (event, listener) {
if (typeof self.events[event] !== 'object') {
self.events[event] = []
}
self.events[event].push(listener)
}
self.removeListener = function (event, listener) {
let idx
if (typeof self.events[event] === 'object') {
idx = self.events[event].indexOf(listener)
if (idx > -1) {
self.events[event].splice(idx, 1)
}
}
}
self.emit = function (event) {
var i, listeners, length, args = [].slice.call(arguments, 1);
if (typeof self.events[event] === 'object') {
listeners = self.events[event].slice()
length = listeners.length
for (i = 0; i < length; i++) {
listeners[i].apply(self, args)
}
}
}
self.once = function (event, listener) {
self.on(event, function g () {
self.removeListener(event, g)
listener.apply(self, arguments)
})
}
}
let eventMixin = {
/**
* Subscribe to event, usage:
* menu.on('select', function(item) { ... }
*/
on(eventName, handler) {
if (!this._eventHandlers) this._eventHandlers = {};
if (!this._eventHandlers[eventName]) {
this._eventHandlers[eventName] = [];
}
this._eventHandlers[eventName].push(handler);
},
/**
* Cancel the subscription, usage:
* menu.off('select', handler)
*/
off(eventName, handler) {
let handlers = this._eventHandlers && this._eventHandlers[eventName];
if (!handlers) return;
for (let i = 0; i < handlers.length; i++) {
if (handlers[i] === handler) {
handlers.splice(i--, 1);
}
}
},
/**
* Generate the event and attach the data to it
* this.trigger('select', data1, data2);
*/
trigger(eventName, ...args) {
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
return; // no handlers for that event name
}
// call the handlers
this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
}
};
// @flow
// An event handler can take an optional event argument
// and should not return a value
type EventHandler = (event?: any) => void;
type WildCardEventHandler = (type: string, event?: any) => void
// An array of all currently registered event handlers for a type
type EventHandlerList = Array<EventHandler>;
type WildCardEventHandlerList = Array<WildCardEventHandler>;
// A map of event types and their corresponding event handlers.
type EventHandlerMap = {
'*'?: WildCardEventHandlerList,
[type: string]: EventHandlerList,
};
/** Mitt: Tiny (~200b) functional event emitter / pubsub.
* @name mitt
* @returns {Mitt}
*/
export default function mitt(all: EventHandlerMap) {
all = all || Object.create(null);
return {
/**
* Register an event handler for the given type.
*
* @param {String} type Type of event to listen for, or `"*"` for all events
* @param {Function} handler Function to call in response to given event
* @memberOf mitt
*/
on(type: string, handler: EventHandler) {
(all[type] || (all[type] = [])).push(handler);
},
/**
* Remove an event handler for the given type.
*
* @param {String} type Type of event to unregister `handler` from, or `"*"`
* @param {Function} handler Handler function to remove
* @memberOf mitt
*/
off(type: string, handler: EventHandler) {
if (all[type]) {
all[type].splice(all[type].indexOf(handler) >>> 0, 1);
}
},
/**
* Invoke all handlers for the given type.
* If present, `"*"` handlers are invoked after type-matched handlers.
*
* @param {String} type The event type to invoke
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
* @memberOf mitt
*/
emit(type: string, evt: any) {
(all[type] || []).slice().map((handler) => { handler(evt); });
(all['*'] || []).slice().map((handler) => { handler(type, evt); });
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment