'Using readline module in node.js, how do I ask a certain number of questions, but not ask the next question before previous answer is received
For example, if this is my code
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
});
for(var i = 0;i<7;i++){
rl.question('What is your name? ', function(name){
console.log("Your name is " + name);
});
}
then when I run it in the CLI what I am prompted is
What is your name?What is your name?What is your name?What is your name?What is your name?What is your name?What is your name?
How do I make it such that it asks "What is your name?", then gets an answer, then displays the output, and then repeats this 6 more times. Thank you!
Solution 1:[1]
By default, the question method is callback-based. Meaning that in order to ask the second question, you'll need to call the 2nd rl.question inside the callback of the first question call.
This approach is very brittle and won't scale at all in your case because you would end up with a deep pyramid of nested callbacks.
So, one strategy could be to turned this callback-based API into a promise-based one. Fortunately, Node.js offer a handy promisify helper available in the util module that can perform this transformation.
This is detailed in the official doc: https://nodejs.org/dist/latest-v15.x/docs/api/readline.html
With this new promisified question function returning a promise, you can now use the async/await syntax to obtain what you expect:
var readline = require('readline');
var util = require('util');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
var question = util.promisify(rl.question).bind(rl);
async function ask() {
for(var i = 0;i<7;i++){
try {
var name = await question('What is you name? ');
console.log("Your name is " + name);
} catch (err) {
console.error('Question rejected', err);
}
}
rl.close();
}
ask()
Solution 2:[2]
util.promisify gets you close, but it expects a function of two arguments: An error and a value. rl.question does not satisfy this interface: it always calls the function with one argument which is the input. util.promisify sees this input as non-null and hence assumes an error occurred.
Fortunately, util.promisify is a super simple function and we can rewrite it ourselves to work in this use case.
const question = (...args) => new Promise((res, rej) => rl.question(...args, res));
Now question is a function which produces a promise. We can async it. The rest of the code works as in Delapouite's answer
async function ask() {
for(var i = 0;i<7;i++){
try {
var name = await question('What is you name? ');
console.log("Your name is " + name);
} catch (err) {
console.error('Question rejected', err);
}
}
rl.close();
}
ask()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Delapouite |
| Solution 2 | Silvio Mayolo |
