The readline module in Node.js is a built-in interface that allows reading a stream (like process.stdin) on a line-by-line basis. It is particularly useful when you want to read user input from the command line or read a large file line by line to save memory. In this topic, you will explore the properties and methods of the readline module.
Create interface
To interact with a user, you need to create an interface object for both the input and the output:
// import the readline module
const readline = require('readline');
// create interface
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
Here, the createInterface() method takes two arguments. The first one is for the standard input — process.stdin, and the second one is for the standard output — process.stdout. The createInterface() method can take other optional arguments like completer which is used for Tab autocompletion. You can check the full list of optional arguments.
process.stdin and process.stdout are built-in streams provided by Node.js. They are associated with the standard input and standard output of the process respectively. process.stdin is a readable stream and it is commonly used to read data from the console in command-line programs. For example, you can use it to read users' responses to prompts. process.stdout is a writable stream and it is commonly used to print data to the console. For instance, when you use console.log(), the command is actually written to process.stdout.Ask a question
To ask a question to the user and read the output, use the rl.question() method. Take a look at the following snippet:
// ask a question
rl.question('What is your name? ', (answer) => {
console.log(`Nice to meet you, ${answer}`);
// close the interface
rl.close();
});
In this example, rl.question is used to ask the user a question. The user's response is then passed as an argument to the callback function, which logs a greeting to the console. The rl.close method is used to close the readline interface once the user interaction is complete. If you don't close the interface, the program waits for user input indefinitely.
The output of the program will be:
What is your name? Bert
Nice to meet you, BertSet and handle a prompt
You can also set specific prompts and use them in your program:
// set the prompt
rl.setPrompt('Enter your age: ');
// display the prompt
rl.prompt();
// handle user input
rl.on('line', (input) => {
console.log(`Age of the user: ${input}`);
rl.close();
});
In this example, rl.setPrompt('Enter your age: '); sets the prompt that is displayed when rl.prompt() is called. When the user types a line of text and presses Enter key, the 'line' event is triggered, and the callback function is called with the line of text that the user typed.
Note that rl.on('line', callback) sets a listener for the 'line' event, which is emitted whenever the input stream receives an end-of-line input (\n, \r, or \r\n). This way, it is possible to get the user's input after they type it.
The output of the program is:
Enter your age: 25
Age of the user: 25Events
The Node.js readline module provides several events that you can listen to. Here are some of the common events:
- 'line' — This event is emitted whenever the input stream receives an end-of-line input, for example,
\n,\r, or\r\n. The listener function is called with a string that contains a single line of the received input. - 'close' — This event is emitted when
rl.close()is called. The input stream receives its 'end' event, or the input stream is provided with theSIGINTevent —Ctrl+C. This typically means the user has finished their input. - 'pause' — This event is emitted when the input stream is paused.
- 'resume' — This event is emitted when the input stream is resumed.
- 'SIGINT' — This event is emitted whenever the input stream receives a
SIGINTevent, typically as a result of the user pressingCtrl+C. This is often used to handle custom cleanup or other tasks when the user interrupts the program.
These events provide a lot of flexibility in handling user input and help control the behavior of your command-line interface. You can check the rest of the events on the official Node.js documentation page.
Here's an example that implements all of the mentioned events:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('What is your name? ', (name) => {
console.log(`Hello, ${name}!`);
rl.on('line', (input) => {
console.log(`You typed: ${input}`);
});
rl.on('pause', () => {
console.log('Readline paused.');
});
rl.on('resume', () => {
console.log('Readline resumed.');
});
rl.on('SIGINT', () => {
console.log('SIGINT received. Exiting...');
rl.close();
});
rl.on('close', () => {
console.log('Readline closed.');
process.exit(0);
});
});Use cases
The readline module in Node.js is a tool for handling user input and output in console-based applications. Here are a few things you can do with it:
-
Interactive Command Line Interfaces (CLIs):
readlineis great for creating interactive command-line applications. You can ask questions, get user input, and respond accordingly. -
Read large files line by line: If you have a large text file that you want to process one line at a time (for example, to save memory), you can use
readline. This is much more efficient than reading the entire file into memory. -
Build text-based games: You can use
readlineto create interactive, text-based games. As a simple starting point, you can create a simple quiz game that asks questions and waits for user responses. -
Prompt for passwords: You can use
readlineto prompt users for passwords and other sensitive information. You can even configure it to hide the input as the user types. -
Create a REPL: You can use
readlineto create a Read-Eval-Print Loop (REPL), which is a simple and interactive programming environment.
To see the readline module in action, let's create a simple game of rock-paper-scissors:
const readline = require('readline');
const rl = readline.createInterface(process.stdin, process.stdout);
const choices = ['rock', 'paper', 'scissors'];
let computerChoice = choices[Math.floor(Math.random() * choices.length)]; // generate random number
rl.question('Choose rock, paper, or scissors: ', (playerChoice) => {
playerChoice = playerChoice.toLowerCase(); // handle different cases
// handle errors if the user types an unexpected value
if (!choices.includes(playerChoice)) {
console.log('Invalid choice. Please choose rock, paper, or scissors.');
rl.close();
return;
}
console.log('Player choice:', playerChoice);
console.log('Computer choice:', computerChoice);
if (playerChoice === computerChoice) {
console.log('It\'s a tie!');
} else if (
(playerChoice === 'rock' && computerChoice === 'scissors') ||
(playerChoice === 'paper' && computerChoice === 'rock') ||
(playerChoice === 'scissors' && computerChoice === 'paper')
) {
console.log('Player wins!');
} else {
console.log('Computer wins!');
}
rl.close(); // close the interface
});
In this game, the program asks the player to choose one from rock, paper, or scissors. The computer also makes a random choice. The game then compares the player's choice with the computer's choice to determine the winner by following the standard rules of rock-paper-scissors:
- Rock crushes scissors,
- Scissors cuts paper,
- And paper covers rock.
If the player and the computer make the same choice, then it's a tie.
Conclusion
In this topic, you looked at the readline module in Node.js. It is an effective utility for managing user input and output in console-based applications. You now know how to create an interface to interact with the user and listen to different events that the readline module has. You also looked at some of the use cases for the readline module. Now, it's time to practice what you've learned.