🟢 Node.js Q22 / 118

What are the types of streams?

AI-Powered Answer ✓ Answered

Node.js streams are a powerful mechanism for handling data flow, especially when dealing with large amounts of data or data that arrives in chunks. They allow you to process data piece by piece, without needing to load the entire dataset into memory.

Understanding Node.js Streams

At its core, a stream is an abstract interface for working with streaming data in Node.js. Many built-in Node.js modules implement the stream interface, including fs for file operations, http for network requests, and zlib for compression. Streams are instances of EventEmitter.

The Four Core Stream Types

There are four fundamental types of streams in Node.js, each serving a distinct purpose in data manipulation:

1. Readable Streams

Readable streams are abstractions from which data can be consumed. Examples include fs.createReadStream() for reading files, http.IncomingMessage for incoming HTTP requests on a server, and process.stdin.

javascript
const fs = require('fs');
const readableStream = fs.createReadStream('input.txt');

readableStream.on('data', (chunk) => {
  console.log(`Received ${chunk.length} bytes of data.`);
});

readableStream.on('end', () => {
  console.log('Finished reading data.');
});

readableStream.on('error', (err) => {
  console.error('Error:', err);
});

2. Writable Streams

Writable streams are abstractions to which data can be written. Examples include fs.createWriteStream() for writing files, http.ServerResponse for responses from an HTTP server, and process.stdout and process.stderr.

javascript
const fs = require('fs');
const writableStream = fs.createWriteStream('output.txt');

writableStream.write('Hello, world!\n');
writableStream.write('This is a writable stream example.\n');
writableStream.end(); // Signifies that no more data will be written

writableStream.on('finish', () => {
  console.log('All data has been written to file.');
});

writableStream.on('error', (err) => {
  console.error('Error:', err);
});

3. Duplex Streams

Duplex streams are both Readable and Writable. They can be read from and written to simultaneously. Examples include TCP sockets (net.Socket), where you can read data sent by the peer and write data to the peer using the same stream object.

javascript
const net = require('net');

const server = net.createServer((socket) => {
  // 'socket' is a Duplex stream
  socket.on('data', (data) => {
    console.log('Received from client:', data.toString());
    socket.write('Echo: ' + data.toString()); // Write back to client
  });

  socket.on('end', () => {
    console.log('Client disconnected.');
  });
});

server.listen(3000, () => {
  console.log('Server listening on port 3000');
});

4. Transform Streams

Transform streams are a type of Duplex stream that can modify or transform the data as it is written and then read. They act as a filter, taking input, performing operations, and then providing output. Examples include zlib streams (gzip, deflate) for compression/decompression and crypto streams for encryption/decryption.

javascript
const zlib = require('zlib');
const fs = require('fs');

const gzip = zlib.createGzip(); // A Transform stream

const readable = fs.createReadStream('input.txt');
const writable = fs.createWriteStream('input.txt.gz');

readable.pipe(gzip).pipe(writable);

writable.on('finish', () => {
  console.log('File successfully gzipped.');
});

writable.on('error', (err) => {
  console.error('Error during gzip:', err);
});

The `pipe()` Method

The pipe() method is a crucial feature of Node.js streams. It provides a simple way to connect the output of a Readable stream to the input of a Writable stream, automatically handling backpressure to prevent the Writable stream from being overwhelmed by data from the Readable stream. It makes chaining stream operations very straightforward.