Hiprup

How do you implement a simple pub/sub event emitter?

A pub/sub (publish–subscribe) emitter lets parts of an app communicate through named events, without direct references.

  • subscribe(event, fn) — register a listener under the event name.

  • publish(event, data) — call every listener registered for that event with the data.

  • unsubscribe — remove a listener so it stops receiving events.

Benefit: loose coupling — publishers and subscribers don't need to know about each other.

class EventBus {
  #events = {};

  subscribe(event, callback) {
    (this.#events[event] ??= []).push(callback);
    // Return unsubscribe function
    return () => {
      this.#events[event] = this.#events[event].filter(cb => cb !== callback);
    };
  }

  publish(event, ...data) {
    (this.#events[event] ?? []).forEach(cb => cb(...data));
  }

  subscribeOnce(event, callback) {
    const unsub = this.subscribe(event, (...args) => {
      callback(...args);
      unsub();
    });
  }
}

// Usage
const bus = new EventBus();

const unsub = bus.subscribe('message', (text, sender) => {
  console.log(`${sender}: ${text}`);
});

bus.subscribe('message', (text) => {
  console.log(`Log: ${text}`);
});

bus.publish('message', 'Hello!', 'John');
// 'John: Hello!'
// 'Log: Hello!'

unsub(); // Remove first subscriber
bus.publish('message', 'World!', 'Jane');
// 'Log: World!' (only second subscriber)

#events stores arrays of callbacks per event. subscribe adds a callback and returns an unsubscribe function (closure). publish calls all callbacks for the event. subscribeOnce auto-unsubscribes after first call. ??= lazily initializes the array. Private #events prevents external access.

Implement subscribe (with unsubscribe return), publish, and once — this is a common interview coding question. The unsubscribe closure is the key detail.

Using private fields (#events) and ??= shows modern JS. This is the foundation for Redux, custom event systems, and component communication.

How do you implement a simple pub/sub event emitter? | Hiprup