Inside Node.js Readable Streams: Initialization, Modes, and Back‑Pressure Mechanics

This article dissects Node.js Readable streams, explaining their initialization, internal state management, the distinction between flowing and paused modes, and how back‑pressure is handled, all illustrated with real source‑code examples and diagrams.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
Inside Node.js Readable Streams: Initialization, Modes, and Back‑Pressure Mechanics

Introduction

Stream is the abstract interface for handling streaming data in Node.js and underlies HTTP request and response objects. Node.js defines four basic stream types—Readable, Writable, Duplex, and Transform. This article examines the internal execution mechanism of Readable streams by analysing the source code of Node.js v16.2.0.

Readable Initialization

All readable streams implement stream.Readable and must override the _read method to fetch data from an underlying resource pool.

const Readable = require('stream').Readable;
class CustomReadable extends Readable {
  constructor(dataSource, options) {
    super(options);
    this.dataSource = dataSource;
  }
  // Must override _read to call push and read from the underlying source
  _read() {
    const data = this.dataSource.makeData();
    const result = this.push(data);
    console.log('Can push more data:', result);
  }
}

Note: a readable stream has no data of its own; it must implement _read to push data into its internal buffer.

Two Modes

Readable streams operate in either flowing or paused mode, which determines how data chunks are delivered to consumers.

Flowing Mode

In flowing mode the stream automatically reads data and emits it via the data event.

Paused Mode

In paused mode the stream does not emit data automatically; the consumer must register a readable event and call read() to retrieve data.

The internal state is stored in this._readableState and includes properties such as highWaterMark, buffer, length, flowing, ended, and others that control the lifecycle.

Paused Mode Details

The lifecycle can be described with five states: start, reading, normal, ended, and endEmitted. The highWaterMark (default 16 KB) defines the buffer water level; when the buffer size is below this value the stream reads more data.

Example: a custom readable with a simulated source of 25 000 bytes that pushes 5 000‑byte chunks.

const dataSource = {
  data: new Array(25000).fill('1'),
  makeData() {
    if (!dataSource.data.length) return null;
    return dataSource.data.splice(dataSource.data.length - 5000)
      .reduce((a, b) => a + '' + b);
  }
};
const customReadable = new CustomReadable(dataSource);

When a readable listener is added, the stream enters the reading state, fetches data via _read, pushes it into the buffer, and then repeatedly calls stream.read(0) (via maybeReadMore) until the buffer reaches the high‑water mark, after which it emits a readable event.

Flowing Mode Details

Registering a data listener switches the stream to flowing mode. The resume method triggers an initial stream.read(0) and then repeatedly calls stream.read() inside a flow loop, emitting each chunk through the data event.

Example: the same custom readable emits data events, pauses after 10 000 bytes, waits one second, then resumes.

let consumer = '';
customReadable.on('data', (chunk) => {
  consumer += chunk;
  if (consumer.length === 10000) {
    console.log('**Pause stream**');
    customReadable.pause();
    setTimeout(() => {
      console.log('**Resume stream**');
      customReadable.resume();
    }, 1000);
  }
});

Calling pause() sets state.flowing = false, stopping the flow loop; resume() restores it.

Personal Understanding

In paused mode the “normal” state is reached when the internal buffer reaches highWaterMark and no further reads are needed. In flowing mode the “normal” state is when the consumer explicitly pauses the stream, shifting control of back‑pressure to the consumer.

Notes and References

Diagrams and source files are linked in the original article. References include several deep‑dive posts on Node.js stream internals.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptNode.jsStream APIbackpressureReadable Stream
Taobao Frontend Technology
Written by

Taobao Frontend Technology

The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.