12

As the title states, I was wondering if it is possible to use promisify (https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original) for readline in node.js? I was only able to do it like this:

let data = [];
const parse = () => {
    return new Promise((resolve, reject) => {

        const rl = readline.createInterface({
            input: fs.createReadStream(path)
        });

        rl.on('line', (line) => {
            data.push(line);
        });

        rl.on('close', () => {
            resolve(data);
        });
    });
};
6
  • You can only promisify error first callbacks, and with promisify.custom other types of callbacks that does not follow the pattern. For streams and event emitters you need to implement your own logic, it does share a common interface (with on close, on finish ) but the usecases are very different. Commented Oct 24, 2017 at 10:35
  • Yeah, that's what I suspected. Is my implementation adequate? Commented Oct 24, 2017 at 10:48
  • 2
    The problem with your implementation is that you added the data in a higher scope than your promise, it will accumulate data for each parse use, if you use parse promise 2 times, the second use will have the first values appended and then the second values also. A better approach is to set the let data in the promise in this way for each use you will store only the new data. Commented Oct 24, 2017 at 10:54
  • you are absolutely right, I completely forgot that! Commented Oct 24, 2017 at 10:57
  • 1
    Have a look at stackoverflow.com/questions/43638105/… Commented Jun 5, 2021 at 19:52

4 Answers 4

17

Here you have a simple way to do it that doesn't use promisify:

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

function question(query) {
    return new Promise(resolve => {
        readline.question(query, resolve);
    });
}

async function main() {
    const name = await question('Whats your name? ');
    console.log(`hello ${name}!`);
    readline.close();
}

main();
Sign up to request clarification or add additional context in comments.

1 Comment

starting in node 17, you can simply do readline = require('readline').promises.createInterface(...) and then just invoke await readline.question('...') directly, see nodejs.org/api/readline.html#class-readlinepromisesinterface
7

Here is an example of how I promisify readline.question:

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

// Prepare readline.question for promisification
readline.question[promisify.custom] = (question) => {
  return new Promise((resolve) => {
    readline.question(question, resolve);
  });
};

// Usage example:
(async () => {
  const answer = await promisify(readline.question)('What is your name? ');
  readline.close();
  console.log('Hi %s!', answer);
})();

Node (v8) documentation for custom promisified functions: https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_custom_promisified_functions

Comments

0

try to use bluebird which create http://bluebirdjs.com/docs/api/promise.promisifyall.html

but if the code works. then I think you don't need to promisify that since you already return it as promise.

Comments

0

Starting in Node 17, it's already promisified:

import { stdin, stdout } from 'node:process';
import * as readline from 'node:readline/promises';

const rl = readline.createInterface({ input: stdin, output: stdout });
const answer = await rl.question('What is your name? ');
console.log('Thank you', answer);
rl.close();

See the documentation:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.