4

Please read this very short article to get up to speed on what I am trying to do.

the main point is that, as the author says, I "need to ask the user several questions, ...validate the input data and re-ask questions when something was entered wrong." Furthermore, I might need to do more complex things to validate the input, aside from checking it against a regular expression. Like, for example, check to make sure the current input wasn't entered by the user at an earlier prompt.

I am interested in refactoring the main code snippet from this article so that it is promise-based. The obvious reason why I want to do this is to avoid callback hell in the event that i need to prompt the user more than two or three times. Do you have any suggestions on how to go about refactoring this? The thing that is tripping me up is the recursive call to ask(), and also the fact that if a promise fails, thats it: its done. Whereas this code needs to loop over and over again until it gets valid input. SO I don't even really know where to start.

Also, if you have any "gordian knot"-type solutions, I am open to going in a completely different direction. Maybe Node has a built-in library for doing this kind of stuff that I am not aware of? Maybe readline? I don't know though cuz I am too new to this stuff and the readline API doesnt really make much sense to me...

Basically, if you can think of ANY way to refactor this so that I don't have to go deep into a callback nightmare, I would be grateful :)

Anyway, here is the code snippet in full:

function ask(question, format, callback) {
 var stdin = process.stdin, stdout = process.stdout;

 stdin.resume();
 stdout.write(question + ": ");

 stdin.once('data', function(data) {
   data = data.toString().trim();

   if (format.test(data)) {
     callback(data);
   } else {
     stdout.write("It should match: "+ format +"\n");
     ask(question, format, callback);
   }
 });
}
2
  • I don't understand the problem. The author talks about how 'when the user presses enter, you have to figure out which question the user is on.' which seems very simple to me, just keep asking the same question until the answer is valid. So if you change the once to an .on('data'), you don't need recursion, the stream will keep being ready to read the next input. Just put all questions in an array and track the index of the current question. If the answer is ok, next question, else ask the same one. Commented Jan 19, 2018 at 14:09
  • hi @Shilly . How would you "ask the same one" without calling ask() again? Commented Jan 19, 2018 at 16:38

2 Answers 2

5

At first, promisify the stdin reader:

function askOnce(question){
  var stdin = process.stdin, stdout = process.stdout;

  stdin.resume();
  stdout.write(question + ": ");

  return new Promise(res => {
    stdin.once('data', function(data) {
      res(data.toString().trim());
    });
  });
}

So no asking is easy:

async function ask(question, format){
  let answer;

  do {
    answer = await askOnce(question);
  } while(!answer.test(format));

  return answer;
}

Without async / await its a bit uglier (using recursion and the promise flattening mechanism):

 function ask(question, format){
   return askOnce(question).then(answer =>  {
      if(!answer.test(format))
         return ask(question, format);
      return answer;
  });
}
Sign up to request clarification or add additional context in comments.

3 Comments

crap, just realized i cant do a full code snippet in comments
Thanks Jonas. Looks like this is on the right track. How would you use your async function ask()? like this? ask('first question', /D/).then((data) => { // do something with first input }).then(() => { ask('second question', /y|n/).then((data) => { // do something with second input })
@jeff B exactly like this. Just try it ;)
1

are you reinventing the wheel? why not use the prompt module? this takes user input from the command prompt in a promise based manner.

https://www.npmjs.com/package/prompt

2 Comments

haha. yea, this was the kind of "gordian knot" solution I mentioned. I've been searching for something like this. Wonder why i never found it?????
I don't think prompt is promised based, actually. But it's very easy to use promisify util to make it promise-y.

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.