Streams

A story about streaming MySQL results

Paginated query -> slow

A story about streaming MySQL results

Streamed query -> overload memory

A story about streaming MySQL results

Streamed query with setting fetch size -> 15 times faster

Motivations

Use case 1: Huge inputs

  • Huge inputs are likely to be transported by several chunks
  • Loading all before processing is a waste of time
  • Loading all before processing is a waste of memory
  • Input chunks can be processed asap
  • Input stream can be paused to limit memory consumption and prevent crashes

Use case 2: Composing processes

  • Data flows can often be designed as composable independent scalable processes
  • Streams can be composed by piping streams to others with backpressure

Examples

  • HTTP requests and responses
  • TCP sockets
  • File system
  • zlib
  • crypto
  • process (also child processes)

Concepts

Streams

  • are event emitters
  • implement readable, writable, or both interfaces
  • initially transport buffers or strings
  • have an object mode to transport arbitrary values

Readable streams

  • can be read
  • can end
  • can be piped to a writable stream
  • can be paused

Writable streams

  • can be written
  • can be finished

Events

Readable streams

  • readable
  • data
  • error
  • end
  • close

Writable streams

  • drain
  • pipe/unpipe
  • error
  • finish
  • close

Streams (from implementer side)

Additionally, the stream implementer can

  • implement _read method of Readable streams
  • implement _write method of Writable streams
  • implement _transform method of Transform streams

Dive deeper

We scratch the surface. To dive deeper, you can read this stream handbook (quite old though)

Examples

Built-in streams: process

process.stdin
  .pipe(process.stdout);

Pipe stdin to stdout

process.stdin
  .pipe(new stream.PassThrough())
  .pipe(process.stdout);

Same with an identity transform

Built-in streams: fs

fs.createReadStream('./package.json')
  .pipe(process.stdout);

package.json content written to stdout

// write what you are typing in a file
process.stdin
  .pipe(fs.createWriteStream('./test.txt'));

stdin written to a file

Built-in streams: child_process

// write js files line counts to a file
child_process
  .exec("wc -l `find -name '*.js'`")
  .stdout.pipe(fs.createWriteStream('./line-count.txt'));

shell command output written to a file

Built-in streams: TCP sockets

// client.js

const net = require('net');


const client = new net.Socket();


client.on('connect', () => {
  console.log('client has connected');
});



process.stdin.pipe(client);






client.on('end', () => {
  console.log('client has disconnected');
});



client.connect(3000, 'localhost');
// server.js

const net = require('net');


const server = net.createServer(socket => {


  console.log('client has connected');





  socket.on('data', chunk => {
    console.log('received chunk', chunk);
  });




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

});

server.listen(3000, 'localhost');

Community libraries

​Whole libraries

Micro utilities

Collections

​Core streams mirror

?

Streams

By Alexis Tondelier

Streams

  • 796