How to get synchronous readline or "simulate" it using async in nodejs?

I am wondering if there is an easy way to get a “synchronous” readline, or at least get synchronous I / O in node.js

I use something like this, but it is rather inconvenient

var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); var i = 0; var s1 = ''; var s2 = ''; rl.on('line', function(line){ if(i==0) { s1 = line; } else if(i==1) { s2 = line; } i++; }) rl.on('close', function() { //do something with lines })' 

Instead, I would prefer it to be as simple as something like

 var s1 = getline(); // or "await getline()?" var s2 = getline(); // or "await getline()?" 

Useful conditions:

(a) It is not recommended to use external modules or a file descriptor / dev / stdio, I send the code to the code submission website and they do not work there

(b) May use async / wait or generators

(c) Must be based on a string

(d) No need to read the entire stdin file into memory before processing

+3
readline
source share
6 answers

Here is an example, but this requires reading the entire stdin before yielding results, but this is not ideal.

 var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); function lineiterator() { var currLine = 0; var lines = []; return new Promise(function(resolve, reject) { rl.on('line', function (line){ lines.push(line) }) rl.on('close', function () { resolve({ next: function() { return currLine < lines.length ? lines[currLine++]: null; } }); }) }) } 

Example

 lineiterator().then(function(x) { console.log(x.next()) console.log(x.next()) }) $ echo test$\ntest | node test.js test test 
+2
source share

Using generators, your example would look like this:

 var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); var i = 0; var s1 = ''; var s2 = ''; var iter=(function* () { s1 = yield; i++; s2 = yield; i++; while (true) { yield; i++; } })(); iter.next(); rl.on('line', line=>iter.next(line)) rl.on('close', function() { //do something with lines }) 

So the yield here acts as if it were a blocking getline() and you can process the rows in the usual sequential way.


UPD :
And the asynchronous / pending version might look like this:

 var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); var i = 0; var s1 = ''; var s2 = ''; var continuation; var getline = (() => { var thenable = { then: resolve => { continuation = resolve; } }; return ()=>thenable; })(); (async function() { s1 = await getline(); i++; s2 = await getline(); i++; while (true) { await getline(); i++; } })(); rl.on('line', line=>continuation(line)) rl.on('close', function() { //do something with lines }) 

In both of these "synchronous" versions, i not used to distinguish between lines and is only useful for counting their total number.

+1
source share

Try this. This is still not perfect replication of the synchronous line reading function - for example, async functions still occur later, so some of your calling code may run out of order, and you cannot call it from within the normal for loop - but it is much easier to read than typical .on or .question .

 // standard 'readline' boilerplate const readline = require('readline'); const readlineInterface = readline.createInterface({ input: process.stdin, output: process.stdout }); // new function that promises to ask a question and // resolve to its answer function ask(questionText) { return new Promise((resolve, reject) => { readlineInterface.question(questionText, (input) => resolve(input) ); }); } // launch your program since 'await' only works inside 'async' functions start() // use promise-based 'ask' function to ask several questions // in a row and assign each answer to a variable async function start() { console.log() let name = await ask("what is your name? ") let quest = await ask("what is your quest? ") let color = await ask("what is your favorite color? ") console.log("Hello " + name + "! " + "Good luck with " + quest + "and here is a " + color + " flower for you."); process.exit() } 

UPDATE: https://www.npmjs.com/package/readline-promise implements it (source code here: https://github.com/bhoriuchi/readline-promise/blob/master/src/index.js#L192 ) , It also implements several other functions, but they also seem useful and not too overloaded, unlike some other NPM packages that do the same. Unfortunately, I cannot get it to work due to https://github.com/bhoriuchi/readline-promise/issues/5, but I like its implementation of the central function:

 function ask(questionText) { return new Promise((resolve, reject) => { readlineInterface.question(questionText, resolve); }); } 
+1
source share

Since I don't know how many rows you need, I put them in an array

Feel free to comment if you need a more detailed answer or if my answer is not accurate:

 var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); var i = 0; var strings = []; rl.on('line', function(line) { // 2 lines below are in case you want to stop the interface after 10 lines // if (i == 9) // rl.close() strings[i] = line i++ }).on('close', function() { console.log(strings) }) // this is in case you want to stop the program when you type ctrl + C process.on('SIGINT', function() { rl.close() }) 
0
source share

Like the readline module, there is another readline-sync module that accepts synchronous input.

Example:

 const reader = require("readline-sync"); //npm install readline-sync let username = reader.question("Username: "); const password = reader.question("Password: ",{ hideEchoBack: true }); if (username == "admin" && password == "foobar") { console.log("Welcome!") } 
0
source share

Just in case anyone stumbles here in the future

Node11.7 added support for this doc_link using async await

 const readline = require('readline'); //const fileStream = fs.createReadStream('input.txt'); const rl = readline.createInterface({ input: process.stdin, //or fileStream output: process.stdout }); for await (const line of rl) { console.log(line) } 

don't forget to wrap it in an asynchronous function, otherwise you will get reserver_keyword_error

0
source share

All Articles