It is so easy to use eventEmitter in node.js:
var e = new EventEmitter();
e.on('happy', function(){console.log('good')});
e.emit('happy');
Any client side EventEmitter in browser native?
It is so easy to use eventEmitter in node.js:
var e = new EventEmitter();
e.on('happy', function(){console.log('good')});
e.emit('happy');
Any client side EventEmitter in browser native?
 
    
    In modern browsers, there is EventTarget.
class MyClass extends EventTarget {
  doSomething() {
    this.dispatchEvent(new Event('something'));
  }
}
const instance = new MyClass();
instance.addEventListener('something', (e) => {
  console.log('Instance fired "something".', e);
});
instance.doSomething();
Additional Resources:
Maga Zandaqo has an excellent detailed guide here: https://medium.com/@zandaqo/eventtarget-the-future-of-javascript-event-systems-205ae32f5e6b
MDN has some documentation: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget
Polyfill for Safari and other incapable browsers: https://github.com/ungap/event-target
 
    
    There is a NPM package named "events" which makes you able to make event emitters in a browser environment.
const EventEmitter = require('events')
 
const e = new EventEmitter()
e.on('message', function (text) {
  console.log(text)
})
e.emit('message', 'hello world')
in your case, it's
const EventEmitter = require('events')
const e = new EventEmitter();
e.on('happy', function() {
    console.log('good');
});
e.emit('happy');
 
    
     
    
    This is enough for given case.
class EventEmitter{
    constructor(){
        this.callbacks = {}
    }
    on(event, cb){
        if(!this.callbacks[event]) this.callbacks[event] = [];
        this.callbacks[event].push(cb)
    }
    emit(event, data){
        let cbs = this.callbacks[event]
        if(cbs){
            cbs.forEach(cb => cb(data))
        }
    }
}
Update: I just published little bit more evolved version of it. It is very simple yet probably enough: https://www.npmjs.com/package/alpeventemitter
 
    
    Create a customized event in the client, and attach to dom element:
var event = new Event('my-event');
// Listen for the event.
elem.addEventListener('my-event', function (e) { /* ... */ }, false);
// Dispatch the event.
elem.dispatchEvent(event);
This is referred from: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events Thanks Naeem Shaikh
 
    
    I ended up using this:
export let createEventEmitter = () => {
   let callbackList: (() => any)[] = []
   return {
      on(callback: () => any) {
         callbackList.push(callback)
      },
      emit() {
         callbackList.forEach((callback) => {
            callback()
         })
      },
   }
}
 
    
    2022 update: The BroadcatsChannel may provide a solution.
https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API
 
    
    I have created an npm package that do the same. You can use in Javascript or Typescript event-emitter
Example
import { EventEmitter } from 'tahasoft-event-emitter';
const onStatusChange = new EventEmitter();
function updateStatus() {
  // ...
  onStatusChange.emit();
}
// somewhere else, we want to add a listener when status change
onStatusChange.add(() => {
  // ...
});
 
    
    A very basic solution
function createEventEmitter() {
    const events = {}
    return {
        on: (name, listener) => {
            const listeners = events.hasOwnProperty(name)
                ? events[name]
                : (events[name] = [])
            listeners.push(listener)
        },
        emit: (name, ...params) => {
            const listeners = events[name] || []
            listeners.forEach((listener) => {
                listener(...params)
            })
        },
    }
}
const emitter = createEventEmitter()
emitter.on('myevent', (a, b) => {
    console.log(a, b)
})
emitter.emit('myevent', 1, 2)
 
    
    I like the answer from Alparslan above. Here's one that uses the browser CustomEvent.
let EventEmitter = (function () {
    let elem = document.createElement("div")
 
    return {
        on: function (name, cb) {
            elem.addEventListener(name, (e) => cb(e.detail), false )
        },
        emit: function (name, data) {
            elem.dispatchEvent(new CustomEvent(name, {detail: data}))
        } 
    }
})()
 
    
    Here is a complete code for implementing the EventEmitter class that can be used both in the browser and in node applications. However, I recommend modifying & testing it well before using it.
import { EventEmitter as NodeEventEmitter } from 'events';
type Callback = (params: any) => void | Promise<void>;
const wrapFunction =
    (fn: Callback): Callback =>
    (params: CustomEvent) =>
        fn(params.detail);
export class InBrowserEventEmitter extends EventTarget {
    private _listeners: Record<string, [key: Callback, value: Callback][]> = {};
    private maxListeners = Number.MAX_SAFE_INTEGER;
    public on(eventName: string, fn: Callback) {
        this.addEventListener(eventName, fn);
        return this;
    }
    public once(eventName: string, fn: Callback) {
        const onceCallback = async (params: CustomEvent) => {
            await fn(params);
            this.off(eventName, onceCallback);
        };
        return this.on(eventName, onceCallback);
    }
    public off(eventName: string, fn: Callback) {
        this.removeEventListener(eventName, fn);
        return this;
    }
    public emit(eventName: string, params: unknown) {
        const event = new CustomEvent(eventName, { detail: params });
        return super.dispatchEvent(event);
    }
    public listenerCount(eventName: string): number {
        const eventListeners = this._listeners[eventName];
        return eventListeners ? eventListeners.length : 0;
    }
    public listeners(eventName: string): Callback[] {
        return this._listeners[eventName].map(value => value[0]) || [];
    }
    public eventNames(): string[] {
        return Object.keys(this._listeners);
    }
    public removeAllListeners() {
        this._listeners = {};
        return this;
    }
    public setMaxListeners(maxListeners: number) {
        this.maxListeners = maxListeners;
        return this;
    }
    public getMaxListeners(): number {
        return this.maxListeners;
    }
    public addEventListener(eventName: string, fn: Callback) {
        const wrappedFn = wrapFunction(fn);
        super.addEventListener(eventName, wrappedFn);
        if (!this._listeners[eventName]) {
            this._listeners[eventName] = [];
        }
        this._listeners[eventName].push([fn, wrappedFn]);
    }
    public removeEventListener(eventName: string, fn: Callback) {
        const eventListeners = this._listeners[eventName];
        if (eventListeners) {
            const index = eventListeners.findIndex(item => item[0] == fn);
            if (index !== -1) {
                super.removeEventListener(eventName, eventListeners[index][1]);
                eventListeners.splice(index, 1);
            }
        }
    }
}
// eslint-disable-next-line import/no-mutable-exports
export let EventEmitter: typeof NodeEventEmitter;
if (typeof window === 'undefined') {
    EventEmitter = NodeEventEmitter;
} else {
    // Fallback for the browser environment
    EventEmitter = InBrowserEventEmitter as unknown as typeof NodeEventEmitter;
}
Written with help from an AI Language Modle :-)
 
    
    You need a JavaScript library, like this https://github.com/Olical/EventEmitter?
 
    
    Node gained a native EventTarget in Node 15 (Oct 2020;) this question no longer applies
https://nodejs.org/api/events.html#eventtarget-and-event-api
