myHotTake

Tag: stream examples

  • How Do Node.js Readable and Writable Streams Differ?

    If you find this story helpful, feel free to like or share it with others who might enjoy it too!


    I’m at a river, one that flows endlessly with crystal-clear water. This river represents the world of data in Node.js. Now, in this world, I have two close friends: one is a fisherman named Reed, and the other is a boat builder named Willa.

    Reed, the fisherman, is always focused on what’s coming downstream. He stands by the riverbank with his net, eagerly waiting to catch fish as they swim by. Each fish represents a piece of data. Reed doesn’t know how many fish will come his way or when they’ll arrive, but he stays alert, ready to scoop them up as they appear. Reed’s job is akin to a readable stream—he’s all about receiving data as it flows towards him.

    On the other hand, Willa, the boat builder, has a different task. She stands by the river with a pile of wooden planks, hammering away to create boats. For Willa, it’s not about waiting for fish; it’s about using her resources to build something tangible that can float on the water. She decides when and how to put each plank into place. Willa embodies a writable stream—she’s focused on creating and sending information out into the world, piece by piece.

    As I watch them, I notice how their tasks complement each other perfectly. Reed collects and processes the incoming bounty of fish, while Willa constructs and launches her boats, sending them downstream. Together, they mirror the harmonious dance of data in Node.js, where readable streams (like Reed) capture incoming data and writable streams (like Willa) send out information.

    This river scene helps me understand the seamless flow of data in Node.js, with Reed and Willa each playing their unique roles—one capturing data as it comes, the other sending it out, creating an endless cycle of communication.


    As I stand by the river, watching Reed and Willa, I start to see their roles represented through JavaScript code. Reed, our readable stream, as a stream of data constantly flowing toward us. In Node.js, this is achieved using the fs.createReadStream method, which allows us to read data from a file bit by bit, much like Reed collecting fish.

    Here’s a simple example of Reed in action:

    const fs = require('fs');
    
    // Reed, our readable stream
    const readableStream = fs.createReadStream('example.txt', 'utf8');
    
    readableStream.on('data', (chunk) => {
      console.log('Reed caught a chunk of data:', chunk);
    });
    
    readableStream.on('end', () => {
      console.log('Reed has finished collecting data.');
    });

    In this code, createReadStream opens a file and reads its contents in chunks. The data event is triggered each time a piece of data is read, similar to Reed catching a fish. When all the data has been processed, the end event signifies that Reed has completed his task.

    Now, let’s transition to Willa, our writable stream. She represents the fs.createWriteStream method in Node.js, allowing us to send or write data, much like Willa constructing her boats.

    Here’s Willa at work:

    const writableStream = fs.createWriteStream('output.txt');
    
    // Willa, our writable stream
    writableStream.write('Willa is building her first boat.\n');
    writableStream.write('Willa is adding more to her creation.\n');
    writableStream.end('Willa has finished and launched her boat.\n');

    In this example, createWriteStream opens a file for writing. The write method adds data to the file, akin to Willa adding planks to her boat. The end method signifies that Willa is done with her construction and has sent the final piece downstream.

    Key Takeaways:

    1. Readable Streams: In Node.js, readable streams like Reed allow us to process data as it flows in, using methods like fs.createReadStream to read files in chunks. They are event-driven, relying on data and end events to manage data flow.
    2. Writable Streams: Writable streams like Willa enable us to send or write data, using methods like fs.createWriteStream. They provide methods like write and end to manage data output.
    3. Complementary Roles: Just as Reed and Willa complement each other in the river, readable and writable streams work together in Node.js to handle data efficiently, allowing for simultaneous reading from and writing to various sources.