I know this may come across as a 'Noob Question', and I apologize in advance for asking something so simple. But I haven't been able to find much on this topic when searching online.
I'm trying to write a command line app in Node.js, however I haven't been able to figure out how to handle user input synchronously. I tried using async/await, but those seemed to have no effect. Instead I moved to promises, however the following code errors out with: TypeError: promise.resolve is not a function
.
Reading the MDN it shows the Promise API as being new Promise(resolutionFunc, rejectionFunc)
. With those functions being called on resolution and rejection respectively.
I'm not quite sure what I'm doing wrong, but from what I understand it should only be executing the .then()
after the previous promise is resolved. However that is not the case here:
My Code:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
let numbs = [];
function getInput(i) {
let promise = new Promise((resolve) => {
numbs[i] = resolve;
}, (reject) => {
// do nothing, shouldn't happen
});
rl.question(`Input #${i+1}: `, (input) => {
promise.resolve(Number.parseInt(input));
});
return promise;
}
getInput(0)
.then(getInput(1))
.then(() => {
console.log(numbs)
/*
rest of the program using those 2 inputs
*/
})
.catch((err) => {
// do nothing, and exit
});
Output:
$ node .\file.js
Input #1: Input #1:
[path removed]/file.js:18
promise.resolve(Number.parseInt(input));
^
TypeError: promise.resolve is not a function
at [path removed]/file.js:18:17
at Interface._onLine (readline.js:335:5)
at Interface._normalWrite (readline.js:482:12)
at ReadStream.ondata (readline.js:194:10)
at ReadStream.emit (events.js:315:20)
at addChunk (_stream_readable.js:296:12)
at readableAddChunk (_stream_readable.js:272:9)
at ReadStream.Readable.push (_stream_readable.js:213:10)
at TTY.onStreamRead (internal/stream_base_commons.js:186:23)
There are several things wrong here:
.resolve()
method and that isn't a correct way to wrap r1.question()
in a promise.then(getInput(1))
. You need to pass a function reference to .then()
so it can be called later.Here's a way to fix those problems:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
function getInput(i) {
return new Promise(resolve => {
rl.question(`Input #${i+1}: `, (input) => {
resolve(+input);
});
});
}
let nums = [];
getInput(0).then(val => {
nums.push(val);
return getInput(1);
}).then(val => {
nums.push(val);
console.log(nums)
/*
rest of the program using those 2 inputs
*/
}).catch((err) => {
console.log(err);
});
A simpler version uses async/await
which are really convenient for serializing asynchronous operations:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
function getInput(i) {
return new Promise(resolve => {
rl.question(`Input #${i+1}: `, (input) => {
resolve(+input);
});
});
}
async function run() {
let v1 = await getInput(0);
let v2 = await getInput(1);
console.log(v1, v2);
}
run().catch((err) => {
console.log(err);
});
Note, your code isn't detecting if the user entered something other than a number and your code doesn't terminate the readline stream.
I was able to solve this in a different way than jfriend00 did above, instead of Promises I changed my code to use events and it works functionally the same as theirs. I'm pasting my code here for anyone interested, but I think they have a better answer.
const readline = require('readline');
const { EventEmitter } = require('events');
const events = new EventEmitter();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
let numbs = [];
events.on("input0", () => {
rl.question(`Input #1: `, (input) => {
numbs[0] = Number.parseInt(input);
events.emit("input1");
});
});
events.on("input1", () => {
rl.question(`Input #2: `, (input) => {
numbs[1] = Number.parseInt(input);
events.emit("restOfProgram");
});
});
events.on("restOfProgram", () => {
console.log(numbs);
/*
rest of program to run
*/
});
events.emit("input0");
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.