Skip to content

Chapter 3 of 8

Streams and Buffers

Streams are one of Node.js's most powerful abstractions for handling data. Rather than loading entire files or network payloads into memory, streams process data in chunks as it flows through the application. There are four kinds: Readable streams produce data (such as fs.createReadStream), Writable streams consume data (such as fs.createWriteStream), Duplex streams are both readable and writable (such as a TCP socket), and Transform streams modify data as it passes through (such as zlib.createGzip).

To connect a readable stream to a writable stream, you use the .pipe() method, which automatically manages the flow of data and handles backpressure along the way. The modern alternative is the pipeline() function from stream/promises, which has the advantage of propagating errors automatically and cleaning up resources if any step fails. Without proper piping, manually coordinating streams is error-prone and easy to get wrong.

Backpressure occurs when a writable stream cannot consume data as fast as a readable stream produces it. Node.js signals this condition by having writable.write() return false, indicating that the readable stream should pause. When the writable is ready for more data, it emits a 'drain' event, allowing the readable to resume. Properly handling backpressure is critical for memory efficiency, especially with large files or high-throughput network operations.

Buffers complement streams by providing a way to work with raw binary data. A Buffer is a fixed-size chunk of memory allocated outside the V8 heap, used for handling binary data directly in operations like file I/O, network protocols, and image processing. Buffers can be created with Buffer.alloc(size) for zero-filled memory, Buffer.from(string) for strings, or Buffer.from(array) for raw byte arrays. Common manipulations include buf.toString('utf8') for decoding, buf.slice(start, end) for sub-buffers, and Buffer.concat([buf1, buf2]) for merging. Together, streams and buffers form the foundation for efficient I/O in Node.js.

All chapters
  1. 1Foundations of Node.js and the Event Loop
  2. 2Module Systems
  3. 3Streams and Buffers
  4. 4Asynchronous Programming
  5. 5Building Web Applications with Express
  6. 6Core Built-in Modules
  7. 7Package Management and Project Configuration
  8. 8Error Handling, Process Management, and Events

Drill it

Reading is not remembering. These come from the Nodejs Runtime deck:

Q

What is Node.js?

Node.js is a JavaScript runtime built on Chrome's V8 engine. It allows running JavaScript outside the browser, using an event-driven, non-blocking I/O model tha...

Q

What is the Node.js event loop?

The event loop is the mechanism that allows Node.js to perform non-blocking I/O operations despite JavaScript being single-threaded. It continuously checks the...

Q

What are the phases of the Node.js event loop?

Timers – executes setTimeout and setInterval callbacksPending callbacks – I/O callbacks deferred to next iterationPoll – retrieves new I/O eventsCheck – execute...

Q

What is the difference between setImmediate() and setTimeout()?

setImmediate() executes in the check phase of the event loop, after the poll phase completes. setTimeout(fn, 0) executes in the timers phase on the next iterati...