Node.js Events and the EventEmitter
Node.js handles concurrency with an event-driven model, not threads. "Emitters" fire named events that "listeners" react to, enabling non-blocking I/O for things like file reads and web requests.
WHY IT EXISTS: To manage many concurrent I/O operations, like network requests or database queries, without the overhead of creating a new thread for each one. Traditional blocking code would freeze the entire application while waiting for a task to finish, but Node's event-driven model allows it to remain responsive and handle thousands of connections at once.
THE MENTAL MODEL: Think of a fast-food counter. Instead of one cashier taking an order, making the food, and then taking the next order (blocking), the cashier takes an order and shouts it to the kitchen (emits an event). The kitchen staff (listeners) hear the event and start working. This allows the cashier to keep taking new orders without waiting. In Node.js, the EventEmitter class is the foundation for this pattern.
HOW IT WORKS: Many core Node.js objects inherit from the EventEmitter class. These objects can register listener functions using the .on(eventName, listener) method. When a specific asynchronous operation completes, the object uses the .emit(eventName, ...args) method to trigger the event. This calls all the functions that were registered to listen for that eventName. This entire process is managed by Node's internal event loop, which ensures the main thread is never blocked.
WHEN TO USE IT: This pattern is fundamental to Node.js. It's used for building web servers with the http module (which emits a 'request' event for each incoming connection), reading files with streams (which emit 'data', 'end', and 'error' events), and managing interactions with child processes. It is the default for any asynchronous, non-blocking task.
WHEN NOT TO USE IT: For heavy, CPU-bound tasks like complex mathematical calculations or image processing, this model doesn't help. Since listeners run on the main event loop thread, a long-running listener will block all other operations. For CPU-intensive work, use Worker Threads to run code on a separate thread, preventing it from blocking the event loop.
ONE CANONICAL EXAMPLE: A common pattern is to create a custom class that extends EventEmitter. You can then create an instance of this class and register a listener for a custom event, like 'job-complete', using the .on() method. Later in your code, after some asynchronous work is done, you call .emit('job-complete'). This executes the listener function you defined earlier. A special case is the 'error' event; if emitted with no listener attached, it crashes the Node process by default.
Read the original → nodejs.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.