Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am wondering if there is a simple way to get "synchronous" readline or at least get the appearance of synchronous I/O in node.js

I use something like this but it is quite awkward

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 of this I would prefer if it were as easy as something like

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

Helpful conditions:

(a) Prefer not using external modules or /dev/stdio filehandle, I am submitting code to a code submission website and these do not work there

(b) Can use async/await or generators

(c) Should be line based

(d) Should not require reading entire stdin into memory before processing

like image 396
Colin D Avatar asked Apr 26 '17 15:04

Colin D


People also ask

Is NodeJS asynchronous or synchronous?

NodeJS is an asynchronous event-driven JavaScript runtime environment designed to build scalable network applications. Asynchronous here refers to all those functions in JavaScript that are processed in the background without blocking any other request.

What is synchronous and asynchronous approach in node JS?

Asynchronous functions are generally preferred over synchronous functions as they do not block the execution of the program whereas synchronous functions block the execution of the program until it has finished processing. Some of the asynchronous methods of fs module in NodeJS are: fs.


4 Answers

Just in case someone stumbles upon here in future

Node 11.7 added support for this 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)
}

Remember to wrap it in async function(){} otherwise you will get a reserved_keyword_error.

const start = async () =>{
    for await (const line of rl) {
        console.log(line)
    }
}
start()

To read an individual line, you can use the async iterator manually

const it = rl[Symbol.asyncIterator]();
const line1 = await it.next();
like image 55
Aishwat Singh Avatar answered Oct 23 '22 15:10

Aishwat Singh


Like readline module, there is another module called readline-sync, which takes 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!")
}
like image 29
Jaidee Avatar answered Oct 23 '22 16:10

Jaidee


You can just wrap it in a promise -

const answer = await new Promise(resolve => {
  rl.question("What is your name? ", resolve)
})
console.log(answer)
like image 27
Brian Burns Avatar answered Oct 23 '22 16:10

Brian Burns


I think this is what you want :

const readline = require('readline');

const rl = readline.createInterface({ input: process.stdin , output: process.stdout });

const getLine = (function () {
    const getLineGen = (async function* () {
        for await (const line of rl) {
            yield line;
        }
    })();
    return async () => ((await getLineGen.next()).value);
})();

const main = async () => {
    let a = Number(await getLine());
    let b = Number(await getLine());
    console.log(a+b);
    process.exit(0);
};

main();

Note: this answer use experimental features and need Node v11.7

like image 16
hamid k Avatar answered Oct 23 '22 15:10

hamid k