Topics in this subject
Node.js 3 min read Updated 11 Aug 2026

Events and Streams

Event Emitters and handling massive data using Readable/Writable streams.

🧑‍🏫 Sabse pehle — simple mein samjho#

Frontend mein jaise hum button.addEventListener('click', ...) karte hain, backend mein Node.js ke paas apna khud ka event system hai jise EventEmitter kehte hain. Tum custom events bana sakte ho (jaise 'userRegistered') aur jab wo fire ho, to uske response mein email bhej sakte ho. Dusri badi cheez hai Streams. Agar tumhe 5GB ki movie file serve karni hai, toh tum use ek baar mein memory mein load nahi kar sakte (Server crash ho jayega!). Streams data ko chhote-chhote tukdon (chunks) mein flow karti hain, jaise YouTube pe video buffer hoti hai.

1. EventEmitter#

Much of Node.js's core functionality (including HTTP servers and Streams) is built on top of the EventEmitter class. It implements the Observer design pattern.

const EventEmitter = require('events');

// Create a custom emitter instance
const myEmitter = new EventEmitter();

// 1. Subscribe to an event (The Listener)
myEmitter.on('userRegistered', (username) => {
    console.log(`Sending welcome email to: ${username}`);
});

// You can attach multiple listeners to the same event
myEmitter.on('userRegistered', (username) => {
    console.log(`Adding ${username} to the database`);
});

// 2. Trigger the event (The Emitter)
myEmitter.emit('userRegistered', 'Tarun');

Use cases: Decoupling code. When a user registers, instead of writing all the logic (email, db, analytics) in one massive controller, you just emit an event and let listeners handle the side effects.

2. Streams (Data in Motion)#

Streams are used to handle massive amounts of data continuously without keeping it all in RAM. There are four types of streams, but the most important are Readable (reading data) and Writable (writing data).

The Problem without Streams#

const fs = require('fs');
const server = require('http').createServer();

server.on('request', (req, res) => {
    // ❌ BAD: If the file is 2GB, Node will try to load 2GB into RAM before sending it!
    fs.readFile('huge-video.mp4', (err, data) => {
        res.end(data);
    });
});

The Solution using Streams#

const fs = require('fs');
const server = require('http').createServer();

server.on('request', (req, res) => {
    // ✅ GOOD: Read the file in small chunks
    const readableStream = fs.createReadStream('huge-video.mp4');
    
    // As chunks of data arrive, write them to the response (which is a Writable stream)
    readableStream.on('data', (chunk) => {
        res.write(chunk);
    });
    
    // When finished, end the response
    readableStream.on('end', () => {
        res.end();
    });
    
    // Handle errors (important, otherwise Node might crash if the file is missing)
    readableStream.on('error', (err) => {
        res.statusCode = 500;
        res.end("File not found");
    });
});

The pipe() Shortcut#

Connecting a Readable stream to a Writable stream is so common that Node provides a pipe() method that does all the chunking, writing, and ending automatically!

server.on('request', (req, res) => {
    const readableStream = fs.createReadStream('huge-video.mp4');
    // Read from the file and pipe it directly to the user's browser
    readableStream.pipe(res);
});