简体   繁体   中英

Repeatedly prompt user until resolved using nodeJS async-await

I try repeteadly asking question to user until they gave the correct answer using this code.

The problem is, it won't resolve if the user doesn't gave the right answer at the first time.

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

function promptAge() {
    return new Promise(function(resolve){
        rl.question('How old are you? ', function(answer) {
            age = parseInt(answer);
            if (age > 0) {
                resolve(age);
            } else {
                promptAge();
            }
        });
    });
}

(async function start() {
    var userAge =  await promptAge();
    console.log('USER AGE: ' + userAge);
    process.exit();
})();

Here are the terminal outputs for each condition:

When user gave the right answer the first time it was fine ...

How old are you? 14
USER AGE: 14

When user gave the wrong answer it was stuck (won't resolve and process won't exit) ...

How old are you? asd
How old are you? 12
_

When user doesn't gave any answer it was also stuck ...

How old are you? 
How old are you? 
How old are you? 12
_

Could anyone explain what happened or give me any reference to an article/video that explain this nature?

Btw, i try to do this using async/await for learning purpose (trying to learn how to do things asynchronously). I already tried this without async/await (promptAge() doesn't return any promise) and it was okay.

Thank you for your attention.

It's nothing to do with parseInt() although skellertor is advising good practice.

The problem is that you're generating a new Promise every time promptAge() is called - but the original caller ie start() only has visibility of the first Promise. If you enter a bad input, promptAge() generates a new Promise (inside a never-resolved Promise) and your success code will never run.

To fix this, only generate one Promise. There are more elegant ways to do this but for clarity, and to avoid hacking the code into something unrecognisable...

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

// the only changes are in promptAge()
// an internal function executes the asking, without generating a new Promise
function promptAge() {
  return new Promise(function(resolve, reject) {
    var ask = function() {
      rl.question('How old are you? ', function(answer) {
        age = parseInt(answer);
        if (age > 0) {
          // internal ask() function still has access to resolve() from parent scope
          resolve(age, reject);
        } else {
          // calling ask again won't create a new Promise - only one is ever created and only resolves on success
          ask();
        }
      });
    };
    ask();
  });
}

(async function start() {
    var userAge =  await promptAge();
    console.log('USER AGE: ' + userAge);
    process.exit();
})();

It looks like it has to do with your parseInt() function. In both cases you are passing a non-Number value. First check if it is a number before parsing it into an int.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM