在Node.js中使用readline

8

我正在尝试在else if语句内使用readline

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

rl.question("Would you like to see which cars are available? Please type yes/no: ", function(answer) {

    if (answer === 'yes') {
    // if yes do something
    } else if(answer === 'no') {
        rl.question("Would you like to search by latitude or longitude instead? If yes, please type latitude and longitude: ");
    } else {
        console.log("No worries, have a nice day");
    }

    rl.close();
});

如果用户回答“否”,那么询问另一个问题的正确方式是什么?

目前,如果用户回答“否”,第二个问题将不会被问到。


我只是想知道你是否已经了解了你的代码有什么问题,因为你接受了一个实际上并没有回答你问题的答案? - Molda
4个回答

9

如果我要做这件事,我会首先制作一个基于Promise的readLine问答函数版本:

const question = (str) => new Promise(resolve => rl.question(str, resolve));

我会结构化为一系列步骤:
const steps = {
  start: async () => {
    return steps.seeCars();
  },
  seeCars: async () => {
    const seeCars = await question("Would you like to see which cars are available? Please type yes/no: ");
    if (seeCars === 'yes') { return steps.showCars(); }
    if (seeCars === 'no') { return steps.locationSearch(); }
    console.log('No worries, have a nice day');
    return steps.end();
  },
  showCars: async () => {
    console.log('showing cars');
    return steps.end();
  },
  locationSearch: async () => {
    const longlat = await question("Would you like to search by latitude or longitude instead? If yes, please type latitude and longitude: ");
    return steps.end();
  },
  end: async () => {
    rl.close();
  },
};

如果你是新手,需要注意异步函数的用法,你需要在问题前面打上await关键字,以指示node在问题得到答案之前不要继续进行。此外,还需要注意的是,每当我们更改步骤时,你需要使用return关键字,以防止其他步骤运行。以下是完整的程序供你复制和测试:
const readline = require('readline');

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

// Create a promise based version of rl.question so we can use it in async functions
const question = (str) => new Promise(resolve => rl.question(str, resolve));

// A list of all the steps involved in our program
const steps = {
  start: async () => {
    return steps.seeCars();
  },
  seeCars: async () => {
    const seeCars = await question("Would you like to see which cars are available? Please type yes/no: ");
    if (seeCars === 'yes') { return steps.showCars(); }
    if (seeCars === 'no') { return steps.locationSearch(); }
    console.log('No worries, have a nice day');
    return steps.end();
  },
  showCars: async () => {
    console.log('showing cars');
    return steps.end();
  },
  locationSearch: async () => {
    const longlat = await question("Would you like to search by latitude or longitude instead? If yes, please type latitude and longitude: ");
    return steps.end();
  },
  end: async () => {
    rl.close();
  },
};

// Start the program by running the first step.
steps.start();

1
非常感谢,这正是我所需要的!虽然我对异步函数还比较陌生,但你的示例有助于我理解如何使用它们。 - Sara

1

rl.prompt() 方法将 readline.Interface 实例配置的提示写入输出的新行中,以便为用户提供一个新位置来输入内容。当用户键入“no”以询问不同的问题时,可以使用 setPrompt。

const readline = require('readline');
let lastAnswer = '';
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    prompt: 'Would you like to see which cars are available? Please type yes/no: '
});
rl.prompt();
rl.on('line', (line) => {
    switch (line.trim()) {
       case 'yes':
           lastAnswer = 'yes';
           console.log('great!');
           rl.setPrompt('Would you like to see which cars are available? Please type yes/no: ');
           break;
       case 'no':
           if (lastAnswer === 'no') {
               lastAnswer = '';
               rl.close();
           }
           lastAnswer = 'no';
           rl.setPrompt('Would you like to search by latitude or longitude instead? If yes, please type latitude and longitude: ');
           break;
       default:
           lastAnswer = '';
           console.log(`Say what? I might have heard '${line.trim()}'`);
           break;
    }
    rl.prompt();
}).on('close', () => {
    console.log('Have a great day!');
    process.exit(0);
});

谢谢您的示例,但是如果用户在第二个问题中输入“否”,则该语句将重新询问用户相同的问题(纬度/经度),如果他连续两次输入“否”,我该如何允许用户退出? - Sara
你可以使用一个变量来保存上一个答案,在代码中看到我的更新。 - Pengcheng

0

question 函数需要一个回调函数,否则它会被忽略。 所以,你只需要在 rl.question 中添加一个回调函数来解决问题,因为这是获取答案的唯一方法,而你想知道答案,对吧?

rl.question('...?', function(){});

https://github.com/nodejs/node/blob/master/lib/readline.js#L270

来自 Node.js 源代码:

Interface.prototype.question = function(query, cb) {
  if (typeof cb === 'function') {
    if (this._questionCallback) {
      this.prompt();
    } else {
      this._oldPrompt = this._prompt;
      this.setPrompt(query);
      this._questionCallback = cb;
      this.prompt();
    }
  }
};

0

如果您不想使用readline包,[Inquirer][1]是一个非常好的npm库,支持使用promises。例如:

var inquirer = require('inquirer');
inquirer.prompt([
  {
    type: 'confirm',
    name: 'whichCar',
    message: 'Which car do you want to drive?'
  }
]).then(function(response) {
   if (response.whichCar === true) {
      // do your thing
   } else { 
      // do your second prompt
   }
})

如果你必须使用readline,那么上面的用户已经很好地解释了回调函数需要如何工作。如果不是这样,我认为inquirer是一个强大的选项,具有很多灵活性和定制性。 [1]: https://www.npmjs.com/package/inquirer/v/0.3.5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接