Now that we know how to use events, we can dig into one of my favorite parts of the node.js core: readable & writeable streams.  

First, we'll walk through some examples of piping in Unix-like environments, since it would be good to know what node.js streams are emulating.

Unix Pipeline

Let's look at the contexts of an example text file by using the cat command to output the contents of the file to stdout.

$ cat names.txt 
Gordon
Mike
Brennen
Casey
Toni
Pamela
Nick
Joe
Randy
Ben
Jenny
Tyler
Pete
Chris
Rob
Dave
Jeff
Erik
Paul

Now, let's assume we want to reduce the list of names to names with less than four characters.  We can pipe the output of cat to sed (with a simple regex) to accomplish this.

$ cat names.txt | sed '/.\{4\}/d'
Joe
Ben
Rob

Now that we have filtered the list to get the names we were looking for, let's sort the names in reverse dictonary order by piping the output of sed to sort.

$ cat names.txt | sed '/.\{4\}/d' | sort --dictionary-order --reverse
Rob
Joe
Ben

Pretty neat, huh? By piping the output of one simple program to the input of another simple program, you can accomplish complex tasks easily & quickly without having to have one behemoth program that reads files, filters, sorts, etc. If you'd like to learn more specifically about piping in Unix environments, check out the standard IO section of Brennen Bearnes' userland book

Node.js Streams

Now that you have an idea what inspired the stream API, let's try something similar using the node.js stream pipe() command.

Let's say we want to view the state of the button from our SSH connection. Since stdout is a writable stream, we can pipe the output of the button directly to stdout.  Let's assume we have a tactile button attached to pin 17 on our Raspberry Pi.

First, install the gpio-stream package with npm:

$ npm install gpio-stream

Next, save the following code in a file called stdout.js:

var GpioStream = require('gpio-stream'),
    button = GpioStream.readable(17);

// pipe the button presses to stdout
button.pipe(process.stdout);

That was pretty simple. What if we wanted to redirect the output of our button to light up a LED on pin 18?

var GpioStream = require('gpio-stream'),
    button = GpioStream.readable(17),
    led = GpioStream.writable(18);

// pipe the button presses to the LED
button.pipe(led);

Chunked Transfer Stream

Now that you have a couple simple examples under your belt, let's try something a bit more interesting.  What if we wanted to output our button presses to the LED & a web browser? Since the node.js HTTP server response is a writable stream, we can pipe the button presses to the LED, and then to the HTTP response object. Your browser can receive the presses on the fly using chunked transfer encoding. All of that with ~10 lines of code!

var GpioStream = require('gpio-stream'),
    http = require('http'),
    button = GpioStream.readable(17),
    led = GpioStream.writable(18);

var stream = button.pipe(led);

http.createServer(function (req, res) {
  res.setHeader('Content-Type', 'text/html');
  res.write('<pre>logging button presses:\n');
  stream.pipe(res);
}).listen(8080);

You could pipe the button presses to a file, a web service, or pretty much anything you can think of thanks to the endless number of stream packages available in npm.  The button example is a simple one, but this same concept can be applied to a wide range of sensors.

Speaking of npm, let's examine how to use npm to manage third party packages. We'll even look at how you can create your own npm package and publish it for everyone to use!

This guide was first published on Dec 19, 2014. It was last updated on Mar 08, 2024.

This page (Streams) was last updated on Mar 08, 2024.

Text editor powered by tinymce.