Read From StdIn In JS With Node’s ReadLine

Matthew Lui
4 min readDec 8, 2019

Scanners in Java, readline() in Python, scanf() in C. How is it done in JavaScript?

We’ll be working with Node in a terminal, such as cmd, bash or Visual Studio Code’s terminal. You might be running your program with:

node file-name.js

You can get the code examples and run them here.

Set up

Let’s start by importing the readline library:

const readline = require('readline');

Before we use this object, we’ll need to define an interface for it to use.

To do this, we need one readable and one writable stream. We could make these files or other objects, but today we’ll be using Node’s stdin and stdout, which are properties of Node’s process object.

We’ll place these in an object literal as key-value pairs.

var r1 = readline.createInterface({    input: process.stdin,    output: process.stdout});

Prompting for a Line (adding five)

Now all we need to do is tell our object to ask the user for input and tell it what to do with it.

The readline method question() takes a query to ask in its writable stream, followed by a callback function that tells readline what to do with the line it gets.

r1.question('Give me a number, I\'ll add five! ', function(num) {

// Tell JS this is a number
num = parseInt(num); console.log(num + 5); // Close, or it will keep reading forever r1.close();})

We’ll need to .close() or .pause() the object or it will keep reading lines forever. Why not download the file and see what happens without the close?

Multiple Lines (algorithm input)

Sometimes, particularly in algorithm questions, you might want to:

  1. Read in multiple lines
  2. Parse the input, line-by-line
  3. Call an algorithm, only when you’ve read the entire input

To do this, we’ll take an event-driven approach.

Readline’s .on() takes two arguments: an event and a callback function. Click on the link and take a look at some of the events you can use.

Let’s set up a function that reads lines, then stores the input in an array until it gets too long.

We’ll tell readline what to do in ‘line’ event, which is triggered when a newline character is seen (you press enter in the terminal), with the line itself as the argument.

let inputNumbers = [];r1.on('line', function(line) {    // Put the number in an array    inputNumbers.push(parseInt(line));   // Stop when the array is 5 numbers long   if (inputNumbers.length == 5) {       r1.close();   }});

Let’s try to log our array.

console.log(inputNumbers);

In console:

node test.js
[]
1
2
3
4
5

Uh-oh!

Unfortunately, we haven’t told JavaScript that it needs to finish reading the input before printing the array, so it jumps ahead and prints it whilst it is still empty.

Let’s see. When the array reaches length 5, it calls r1.close(), which triggers the ‘close’ event. So instead of logging directly, let’s do it in the ‘close’ event!

r1.on(‘close’, function() {
// Put your algorithm here. You have access to inputNumbers
// and can be assured all the inputs are in.
console.log(inputNumbers);});

This works just as you’d expect. Here’s the complete program.

Responding to input during a program (even number generator)

We’ll close by writing a program that responds differently depending on terminal input. You might use this for a game, error handling or any other dynamic program.

As an example, let’s write a script that prints even numbers, but we’ll ask the user if they want to continue at every multiple of ten.

This is problematic, because Node will continue to run other code, even if a user hasn’t provided an input.

One approach to using I/O in a synchronous way is the readline-sync library. Install it from the terminal with:

npm install readline-sync

Instead of importing readline, start with:

const readline = require('readline-sync');

We don’t need to set up any interfaces. Just call .question() and Node will wait for our input.

function main() {    count = 0;    while(true) {        count += 2;        console.log(count);        // If a multiple of ten        if (count % 10 == 0) {            answer = readline.question('Continue? Y or N: ');            if (answer == 'N') {                // Stop generating numbers                break;            }        }    }}main();

Try it out here.

What you should know

  1. Node has a readline library.
  2. You need to tell the readline object where to read and write before using it.
  3. Use the question() method to prompt the user for input and run a function based on it.
  4. If you have set the interface, the program hangs until you call close().
  5. Event handling is done with the on() method. The events ‘line’ and ‘close’ are of note.
  6. Switch to the readline-sync library for dynamic programs.

--

--