Bird
Raised Fist0
Node.jsframework~10 mins

Custom event emitter classes in Node.js - Step-by-Step Execution

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
Concept Flow - Custom event emitter classes
Create EventEmitter Class
Add event listener method
Add event emit method
Register listener for event
Emit event with data
Listener runs with data
End
This flow shows how a custom event emitter class is created, listeners are added, and events are emitted to trigger those listeners.
Execution Sample
Node.js
class MyEmitter {
  constructor() {
    this.events = {};
  }
  on(event, listener) {
    (this.events[event] ??= []).push(listener);
  }
  emit(event, data) {
    (this.events[event] ?? []).forEach(fn => fn(data));
  }
}

const emitter = new MyEmitter();
emitter.on('greet', msg => console.log(msg));
emitter.emit('greet', 'Hello!');
Defines a simple event emitter class, adds a listener for 'greet', then emits 'greet' with a message.
Execution Table
StepActionState ChangeOutput
1Create MyEmitter instanceevents = {}
2Call on('greet', listener)events = { greet: [listener] }
3Call emit('greet', 'Hello!')Listener functions called with 'Hello!'Console logs: Hello!
4No more listenersNo state change
5End of executionFinal events = { greet: [listener] }
💡 All listeners for 'greet' have been called, no more events emitted.
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
eventsundefined{}{ greet: [listener] }{ greet: [listener] }{ greet: [listener] }
Key Moments - 2 Insights
Why does the events object hold arrays of listeners instead of single functions?
Because multiple listeners can be registered for the same event, the events object stores an array of functions for each event key, as shown in step 2 of the execution_table.
What happens if emit is called for an event with no listeners?
The emit method uses a fallback empty array (step 3), so no functions run and no errors occur, the state remains unchanged.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 2, what does the events object contain?
A{}
B{"greet": [listener]}
C{"greet": listener}
Dundefined
💡 Hint
Check the 'State Change' column at step 2 in the execution_table.
At which step does the listener function run and output 'Hello!'?
AStep 1
BStep 2
CStep 3
DStep 4
💡 Hint
Look at the 'Output' column in the execution_table for when console logs happen.
If you call emit with an event that has no listeners, what happens to the events object?
AIt stays unchanged
BIt throws an error
CIt adds a new empty array for that event
DIt deletes all listeners
💡 Hint
Refer to the key_moments explanation about emit behavior with no listeners.
Concept Snapshot
Custom event emitter classes:
- Create a class with an events object to hold listeners.
- Use on(event, listener) to add listeners (stored in arrays).
- Use emit(event, data) to call all listeners for that event.
- If no listeners, emit does nothing safely.
- Allows multiple listeners per event.
Full Transcript
This lesson shows how to build a custom event emitter class in Node.js. We start by creating a class with an empty events object. The on method adds listener functions to an array for a given event name. The emit method calls all listeners registered for that event, passing data to them. We traced the steps: creating the instance, adding a listener for 'greet', then emitting 'greet' with a message. The listener runs and logs the message. We also saw that emitting an event with no listeners does nothing and does not cause errors. This pattern lets you build flexible event-driven code.

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