Readline works only for the first time - node.js

I'm using Node's readline but it works only for the first time.
At the first try everything works well (answer is logged and readline is closed) but another time it looks like the readline is not being closed (answer is never logged and console is still waiting for my input even if I've already sent it).
I've class in Node.js (using ES6 with Babel and Nodemon) which has readline in constructor.
class SomeClass
{
constructor(readline) {
this.readline = readline;
}
askPath() {
this.readline.question('Question: ', (answer) => {
console.log(answer);
this.readline.close();
this.askPath();
});
}
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let someClass = new SomeClass(rl);
someClass.askPath();
Console looks like:
> Question: answer
> answer
> Question: second answer
> I can still write
> nothing happens...

Just don't call the .close() function, inside of your callback as it closes the entire readline interface
askPath() {
this.readline.question('Question: ', (answer) => {
console.log(answer);
this.askPath();
});
}
As the documentation says:
The rl.close() method closes the readline.Interface instance and relinquishes control over the input and output streams. [source:nodejs.org]

Related

Custom Node JS REPL input/output stream

I need to have custom REPL input/output stream. for example I need to pass a piece of script to the REPL when some event happens and get it's output and do something with it.
To describe it more clear to you, I'm working on a vscode plugin (github: source code) which provides REPL. in my case I have a vscode WebView and from there, I get user input and then I want to pass that input to the node REPL and get its output and show it to user.
So, how would I achieve that? If you need more information please tell me. thanks in advance.
EDIT 1:
const replServer = repl.start({
input: /* what should be here? */,
output: /* what should be here? */
});
Edit 2:
can anyone explain me what is the usage of input/output parameters in the above example?
Here is a solution that worked for me.
const {
PassThrough
} = require('stream')
const repl = require('repl')
const input = new PassThrough()
const output = new PassThrough()
output.setEncoding('utf-8')
const _repl = repl.start({
prompt: 'awesomeRepl> ',
input,
output
})
_repl.on('exit', function() {
// Do something when REPL exit
console.log('Exited REPL...')
})
function evaluate(code) {
let evaluatedCode = ''
output.on('data', (chunk) => {
evaluatedCode += chunk.toString()
console.log(evaluatedCode)
})
input.write(`${code}\n`)
return result
}
evaluate('2 + 2') // should return 4
Notice created the REPL instance outside the evaluate function so we don't create a new instance for every call of evaluate
To create a repl server you just need to do
const repl = require('repl')
repl.start({prompt: "> ", input: input_stream, output: output_stream");
prompt is a string that is the prompt, stream is the input. input_stream needs to be a readable stream, output_stream needs to be a writable one. you can read more about streams here. Once the streams are working you can do
output_stream.on('data', (chunk) => {
14 //whatever you do with the data
15 });

NodeJs keystrokes get printed twice in console [duplicate]

This question already has answers here:
Get user input through Node.js console
(6 answers)
Closed last month.
I'm new to NodeJs and i'm used to C# were we can use
Console.ReadLine();
I looked into 'readline' and the node prompt package, but it either outputs all the user input twice while entering or, with the 'terminal: false' option, does not allow us to use the backspace.
var stdin = process.openStdin();
stdin.addListener("data", function(d) {
console.log("your input: " + d.toString());
});
This is like you take input value
There is a readline, you can use it like this:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('How are you today? ', (answer) => {
// TODO: Log the answer in a database
console.log(`Thank you for your valuable feedback: ${answer}`);
rl.close();
});
Documentation is available here.

user input with node.js

I have the following Node.js code that behaves strangely:
#!/usr/bin/env node
"use strict";
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function input(prompt) {
rl.question(prompt, function (x) {
rl.close();
console.log("debug: " + x);
return x;
});
}
function main() {
var n = input("Number: ");
// console.log("value: " + n); // problematic line
}
main();
I want to mimic Python's raw_input, i.e. reading a line from the user. After showing the prompt, the program should be blocked until the user presses Enter.
If the "problematic line" is in comments, it works, the program is waiting for input. However, if this line is not in comments, then the program doesn't wait for input and n becomes undefined. Why? How to write a function that returns the user input?
That's because you are expecting the execution of input wait until return is called, which is not how this will work. The problematic line is indeed the previous one. First, input does not return anything, the return statement is the return of the question callback function, but then, you seem to misunderstand the execution flow, as we all have at some point (you'll get it pretty quick after some dead-ends like this one)
Your script is loaded
You declare and define rl, input and main
Main executes
You define n as the result of input
And here is where things start getting asynchronously funny
since question is asynchronous, its execution start but does not block the process
input returns undefined (while you're still waiting for the input)
you print that undefined
You write something on the input
question() finishes its execution and calls the callback (the function you gave as second parameter)
rl is closed
the callback function returns the line, and it is swallowed by the void (this is not technical terminology, just a metaphor)
You may want to do it like this:
#!/usr/bin/env node
"use strict";
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function input(prompt, callback) {
rl.question(prompt, function (x) {
rl.close();
callback(x);
});
}
function main() {
var n = input("Number: ", console.log);
}
main();
If you're new to javascript and node, you may find very useful to use learnyounode and the node code school path or even, if you have the time, the money and the opportunity, read Node.js, MongoDB, and AngularJS Web Development, by Brad Dayley.

Is there a way to get synchronous terminal input in Node.js

I have looked at similar questions on SO and I have an ongoing question about if it is possible to get synchronous input from the command line.
I know about readline and process.stdin.on('readable', ...) but both of those seem to be asynchronous.
I am looking to for a way to prompt the user for input where code later on in my script does not run before there is user input.
May be you can try this in case if you know fix number of inputs you want in sync manner.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let i = 0;
rl.question('Number of inputs : ', (answer1) => {
rl.on('line', (answer2) => {
console.log(`input: ${answer2}`);
i++;
if (i >= answer1) {
rl.close();
}
});
});

Block for stdin in Node.js

Short explanation:
I'm attempting to write a simple game in Node.js that needs to wait for user input every turn. How do I avoid callback hell (e.g. messy code) internal to a turn loop where each turn loop iteration needs to block and wait for input from stdin?
Long explanation:
All the explanations I have read on StackOverflow when someone asks about blocking for stdin input seem to be "that's not what Node.js is about!"
I understand that Node.js is designed to be non-blocking and I also understand why. However I feel that it has me stuck between a rock and a hard place on how to solve this. I feel like I have three options:
Find a way to block for stdin and retain my while loop
Ditch the while loop and instead recursively call a method (like nextTurn) whenever the previous turn ends.
Ditch the while loop and instead use setTimeout(0, ...) or something similar to call a method (like nextTurn) whenever a turn ends.
With option (1) I am going against Node.js principles of non-blocking IO.
With option (2) I will eventually reach a stack overflow as each call adds another turn to the call stack.
With option (3) my code ends up being a mess to follow.
Internal to Node.js there are default functions that are marked **Sync (e.g. see the fs library or the sleep function) and I'm wondering why there is no Sync method for getting user input? And if I were to write something similar to fs.readSync how would I go about doing it and still follow best practices?
Just found this:
https://www.npmjs.com/package/readline-sync
Example code (after doing an npm install readline-sync)
var readlineSync = require('readline-sync');
while(true) {
var yn = readlineSync.question("Do you like having tools that let you code how you want, rather than how their authors wanted?");
if(yn === 'y') {
console.log("Hooray!");
} else {
console.log("Back to callback world, I guess...");
process.exit();
}
}
Only problem so far is the wailing of the "That's not how node is meant to be used!" chorus, but I have earplugs :)
I agree with the comment about moving towards an event based system and would ditch the loops. I've thrown together a quick example of text based processing which can be used for simple text games.
var fs = require('fs'),
es = require('event-stream');
process.stdin
.pipe(es.split())
.on('data', parseCommand);
var actionHandlers = {};
function parseCommand(command) {
var words = command.split(' '),
action = '';
if(words.length > 1) {
action = words.shift();
}
if(actionHandlers[action]) {
actionHandlers[action](words);
} else {
invalidAction(action);
}
}
function invalidAction(action) {
console.log('Unknown Action:', action);
}
actionHandlers['move'] = function(words) {
console.log('You move', words);
}
actionHandlers['attack'] = function(words) {
console.log('You attack', words);
}
You can now break up your actions into discrete functions which you can register with a central actionHandlers variable. This makes adding new commands almost trivial. If you can add some details on why the above approach wouldn't work well for you, let me know and I'll revise the answer.
ArtHare's solution, at least for my use case, blocks background execution, including those started by a promise. While this code isn't elegant, it did block execution of the current function, until the read from stdin completed.
While this code must run from inside an async function, keep in mind that running an async function from a top-level context (directly from a script, not contained within any other function) will block that function until it completes.
Below is a full .js script demonstrating usage, tested with node v8.12.0:
const readline = require('readline');
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
async function blockReadLine() {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
let result = undefined;
rl.on('line', function(line){
result = line;
})
while(!result) await sleep(100);
return result;
}
async function run() {
new Promise(async () => {
while(true) {
console.log("Won't be silenced! Won't be censored!");
await sleep(1000);
}
});
let result = await blockReadLine();
console.log("The result was:" + result);
process.exit(0);
}
run();

Resources