0

我编写了一个简单的 Node.js 程序,它带有一个由inquirer.js提供便利的漂亮菜单系统。但是,在菜单中选择一个选项并完成一些操作后,程序退出。我需要再次显示菜单,直到我在菜单中选择 Exit [last] 选项。我想使用 Promise而不是async/await 来做到这一点。

我尝试使用一个函数来显示菜单并在一个永久循环(例如while (true) { ... })中调用该函数,但这使得程序无法使用。我将其更改为 for 循环只是为了观察问题。下面是简单的程序和结果输出。

PROGRAM

"use strict";

const inquirer = require('inquirer');
const util = require('util')

// Clear the screen
process.stdout.write("\u001b[2J\u001b[0;0H");

const showMenu = () => {
  const questions = [
    {
      type: "list",
      name: "action",
      message: "What do you want to do?",
      choices: [
        { name: "action 1", value: "Action1" },
        { name: "action 2", value: "Action2" },
        { name: "Exit program", value: "quit"}
      ]
    }
  ];
  return inquirer.prompt(questions);
};

const main = () => {
  for (let count = 0; count < 3; count++) {
    showMenu()
    .then(answers => {
      if (answers.action === 'Action1') {
        return Promise.resolve('hello world');
      }
      else if (answers.action === 'Action2') {
        return new Promise((resolve, reject) => {
          inquirer
            .prompt([
              {
                type: 'input',
                name: 'secretCode',
                message: "Enter a secret code:"
              }
            ])
            .then(answers => {
              resolve(answers);
            })
        });
      }
      else {
        console.log('Exiting program.')
        process.exit(0);
      }
    })
    .then((data) => { console.log(util.inspect(data, { showHidden: false, depth: null })); })
    .catch((error, response) => {
      console.error('Error:', error);
    });
  }
}

main()

OUTPUT

? What do you want to do? (Use arrow keys)
❯ action 1
  action 2
  Exit program ? What do you want to do? (Use arrow keys)
❯ action 1
  action 2
  Exit program ? What do you want to do? (Use arrow keys)
❯ action 1
  action 2
  Exit program (node:983) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 keypress listeners added to [ReadStream]. Use emitter.setMaxListeners() to increase limit

如何在第一次调用生成菜单后阻塞,等待选择一个选项并完成相应的操作,然后循环回到显示菜单的下一个迭代?

4

1 回答 1

2

您可以使用async/await语法:

声明你的main函数async,以及await从查询者返回的 Promise:

const main = async () => {
  for (let count = 0; count < 3; count++) {
    await showMenu()
    .then(answers => {
      [...]
  }
};

您的代码无法按预期工作,因为简而言之,解释器在运行任何回调(来自承诺)之前执行同步代码。因此,您的同步for循环在解决任何 I/O 回调之前执行。所有对返回承诺的调用showMenu()都是异步解决的,这意味着不会打印任何内容,并且在循环之前不会解释任何输入。

在函数内编写await块接连同步代码async,这似乎是您正在尝试做的事情。

于 2020-10-21T00:30:33.843 回答