Bird
Raised Fist0
Node.jsframework~5 mins

Custom event emitter classes in Node.js

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction

Custom event emitter classes let you create your own events and respond to them. This helps different parts of your program talk to each other easily.

You want to run some code when something happens, like a file finishes loading.
You need to notify many parts of your app about a change, like a user logging in.
You want to organize your code so events trigger actions without tight connections.
You are building a chat app and want to handle new messages as events.
You want to react to timers or external signals in a clean way.
Syntax
Node.js
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {
  // custom methods or properties can go here
}

const emitter = new MyEmitter();
emitter.on('eventName', () => {
  console.log('Event happened!');
});
emitter.emit('eventName');

Use on to listen for an event.

Use emit to trigger the event and run all listeners.

Examples
This example listens for a 'greet' event and prints 'Hello!' when it happens.
Node.js
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const emitter = new MyEmitter();

emitter.on('greet', () => {
  console.log('Hello!');
});

emitter.emit('greet');
This example shows how to pass data with the event. The listener gets the message and prints it.
Node.js
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const emitter = new MyEmitter();

emitter.on('data', (msg) => {
  console.log('Received:', msg);
});

emitter.emit('data', 'This is a message');
This example adds a custom method to emit an event, making the code cleaner.
Node.js
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {
  sendMessage(msg) {
    this.emit('message', msg);
  }
}

const emitter = new MyEmitter();

emitter.on('message', (msg) => {
  console.log('Message:', msg);
});

emitter.sendMessage('Hi there!');
Sample Program

This program creates a TaskRunner class that emits 'start' and 'finish' events when running a task. Listeners print messages when these events happen. It simulates a task with a 1-second delay.

Node.js
const EventEmitter = require('events');

class TaskRunner extends EventEmitter {
  run(taskName) {
    console.log(`Starting task: ${taskName}`);
    this.emit('start', taskName);
    // Simulate task work with a timeout
    setTimeout(() => {
      this.emit('finish', taskName);
      console.log(`Finished task: ${taskName}`);
    }, 1000);
  }
}

const runner = new TaskRunner();

runner.on('start', (name) => {
  console.log(`Event: Task '${name}' has started.`);
});

runner.on('finish', (name) => {
  console.log(`Event: Task '${name}' has finished.`);
});

runner.run('CleanUp');
OutputSuccess
Important Notes

Always remove listeners if they are no longer needed to avoid memory leaks.

Use once if you want a listener to run only one time.

Event names are case-sensitive strings.

Summary

Custom event emitter classes help your code parts communicate by sending and listening to events.

You create a class extending EventEmitter, then use on and emit to handle events.

This pattern keeps your code organized and easy to extend.

Practice

(1/5)
1. What is the main purpose of creating a custom event emitter class in Node.js?
easy
A. To replace the need for functions and callbacks
B. To allow different parts of your program to communicate by sending and listening to events
C. To speed up the execution of synchronous code
D. To automatically handle HTTP requests

Solution

  1. Step 1: Understand event emitters

    Event emitters let parts of a program send signals (events) and others listen and react to them.
  2. Step 2: Purpose of custom event emitter classes

    Custom classes extend EventEmitter to organize and manage these events clearly.
  3. Final Answer:

    To allow different parts of your program to communicate by sending and listening to events -> Option B
  4. Quick Check:

    Event communication = C [OK]
Hint: Event emitters enable communication between code parts [OK]
Common Mistakes:
  • Thinking event emitters speed up synchronous code
  • Confusing event emitters with HTTP handling
  • Believing event emitters replace all functions
2. Which of the following is the correct way to listen for an event named data in a custom event emitter instance myEmitter?
easy
A. myEmitter.on('data', callback)
B. myEmitter.emit('data', callback)
C. myEmitter.listen('data', callback)
D. myEmitter.trigger('data', callback)

Solution

  1. Step 1: Identify the method to listen for events

    The on method is used to register a callback for an event.
  2. Step 2: Check other options

    emit triggers events, listen and trigger are not valid EventEmitter methods.
  3. Final Answer:

    myEmitter.on('data', callback) -> Option A
  4. Quick Check:

    Listen with on() = A [OK]
Hint: Use on() to listen, emit() to send events [OK]
Common Mistakes:
  • Using emit() to listen instead of on()
  • Using non-existent methods like listen() or trigger()
  • Confusing event names with method names
3. Consider this code snippet:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter();
emitter.on('greet', name => console.log(`Hello, ${name}!`));
emitter.emit('greet', 'Alice');
What will be printed when this code runs?
medium
A. greet Alice
B. Error: greet event not found
C. Hello, Alice!
D. undefined

Solution

  1. Step 1: Understand event registration

    The on method registers a listener for 'greet' that prints a greeting with the name.
  2. Step 2: Understand event emission

    The emit method triggers 'greet' with argument 'Alice', so the listener runs and prints the message.
  3. Final Answer:

    Hello, Alice! -> Option C
  4. Quick Check:

    Emit triggers listener output = B [OK]
Hint: emit() runs on() listeners with given arguments [OK]
Common Mistakes:
  • Expecting event name or arguments to print directly
  • Confusing emit() with on()
  • Assuming error if no listener exists
4. What is wrong with this custom event emitter code?
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter();
emitter.emit('start');
emitter.on('start', () => console.log('Started'));
medium
A. The event name 'start' is invalid
B. emit() cannot be called without arguments
C. You must call super() in the constructor of MyEmitter
D. The event listener is registered after the event is emitted, so it won't run

Solution

  1. Step 1: Check event listener registration timing

    The listener for 'start' is added after the event is emitted, so it misses the event.
  2. Step 2: Validate other options

    emit() can be called without arguments, super() is optional if no constructor, and 'start' is a valid event name.
  3. Final Answer:

    The event listener is registered after the event is emitted, so it won't run -> Option D
  4. Quick Check:

    Listener after emit = no output = D [OK]
Hint: Register listeners before emitting events [OK]
Common Mistakes:
  • Calling emit() before on() listener
  • Thinking emit() needs arguments always
  • Assuming constructor must call super() if none defined
5. You want to create a custom event emitter class that counts how many times an event named ping is emitted. Which code correctly implements this behavior?
hard
A. class PingCounter extends EventEmitter { constructor() { super(); this.count = 0; this.on('ping', () => this.count++); } }
B. class PingCounter extends EventEmitter { constructor() { this.count = 0; this.on('ping', () => this.count++); super(); } }
C. class PingCounter extends EventEmitter { count = 0; on('ping', () => this.count++); }
D. class PingCounter extends EventEmitter { constructor() { super(); this.count = 0; this.emit('ping', () => this.count++); } }

Solution

  1. Step 1: Proper constructor and super() call

    class PingCounter extends EventEmitter { constructor() { super(); this.count = 0; this.on('ping', () => this.count++); } } correctly calls super() first in constructor, required before using this.
  2. Step 2: Correct event listener setup

    class PingCounter extends EventEmitter { constructor() { super(); this.count = 0; this.on('ping', () => this.count++); } } uses this.on('ping', () => this.count++) to increment count on each ping event.
  3. Step 3: Check other options for errors

    class PingCounter extends EventEmitter { constructor() { this.count = 0; this.on('ping', () => this.count++); super(); } } calls this.on before super(), causing error. class PingCounter extends EventEmitter { count = 0; on('ping', () => this.count++); } has invalid syntax outside constructor. class PingCounter extends EventEmitter { constructor() { super(); this.count = 0; this.emit('ping', () => this.count++); } } wrongly uses emit instead of on.
  4. Final Answer:

    class PingCounter extends EventEmitter { constructor() { super(); this.count = 0; this.on('ping', () => this.count++); } } -> Option A
  5. Quick Check:

    super() first, then on() listener = A [OK]
Hint: Always call super() before using this in constructor [OK]
Common Mistakes:
  • Calling this before super() in constructor
  • Using emit() instead of on() to listen
  • Placing on() calls outside constructor or methods