Course contentsShow
← Node.js
Lesson 41 of 1,9801. Node.js Foundations and Runtime InternalsFree lesson

The Event Emitter Pattern Internals

Extend the event emitter to build sophisticated pub-sub messaging architectures.

In this lesson, you will learn how to extend the EventEmitter class to build a custom, decoupled pub-sub (Publisher-Subscriber) messaging architecture.

Beyond Simple Events

Up until now, you have used the EventEmitter to listen for events on objects. In a "Pub-Sub" architecture, we move beyond simple event listening to create a central "Message Bus." This allows different parts of your application to talk to each other without needing direct references to one another.

By extending EventEmitter, you can create specialized classes that manage their own internal event logic, effectively hiding the complexity of your event-driven system behind a clean, public API.

Building a Message Broker

To build this, we create a class that inherits from EventEmitter. This gives our class the ability to register listeners (on) and trigger actions (emit) globally across your application.

const EventEmitter = require('events');

class MessageBroker extends EventEmitter {
  publish(topic, data) {
    console.log(`[Broker] Broadcasting to ${topic}`);
    this.emit(topic, data);
  }

  subscribe(topic, callback) {
    this.on(topic, callback);
  }
}

// Usage
const bus = new MessageBroker();

bus.subscribe('user-login', (user) => {
  console.log(`System: Welcome back, ${user.name}!`);
});

bus.publish('user-login', { name: 'Alice' });

Why extend the class?

When you extend EventEmitter, you aren't just using a tool; you are defining the contract of your messaging system.

  1. Encapsulation: By adding specific methods like publish and subscribe, you restrict how others interact with your events, preventing accidental use of internal methods like removeAllListeners if you don't want them exposed.
  2. Global Coordination: You can create a singleton instance of this broker and share it across your modules. Because it inherits from EventEmitter, it serves as a central clearinghouse where one module can publish a notification when a file is processed, and another can subscribe to that event to update a database or send an email.

This pattern keeps your code decoupled, as the sender of the message doesn't need to know who (or how many) subscribers are listening.

Key Takeaway: Extending EventEmitter allows you to encapsulate your application’s communication logic into a custom message bus, decoupling your modules while providing a standardized interface for event-based coordination.