我编写了一个简单的Node.js程序,并在inquirer.js的帮助下提供了一个很好的菜单系统。但是,在选择菜单中的选项并完成某些操作后,程序将退出。我需要菜单再次显示,直到我选择退出最后一个选项在菜单中。我想用诺言来做这件事,而不是异步/等待。
我尝试使用一个函数来显示菜单,并在一个永久循环(例如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如何阻止在第一次调用之后生成菜单,等待选择一个选项并完成相应的操作,然后循环回显示菜单的下一次迭代?
发布于 2020-10-21 00:30:33
您可以使用async/await语法:
声明您的main函数async,并从inquirer返回的承诺await:
const main = async () => {
for (let count = 0; count < 3; count++) {
await showMenu()
.then(answers => {
[...]
}
};您的代码不像您预期的那样工作,因为简而言之,解释器在运行任何回调(从承诺)之前执行同步代码。因此,在解析任何I/O回调之前,同步for循环都会执行。对showMenu()的所有调用都返回异步解析的承诺,这意味着不会输出任何内容,并且直到循环之后才会解释输入。
在await函数中编写async阻止成功的同步代码,这似乎就是您要做的事情。
发布于 2022-04-26 02:20:44
使用您的代码作为起点,我黑了我自己的库来显示cli菜单。它去掉了大量的问询者的样板,让你简单地声明一个菜单图/树。
main.ts文件显示了您如何使用它。您可以声明一个MenuPrompts字典,您可以在其中添加菜单、操作和LoopActions。每个提示符都有一个键,其他提示可以路由到该键。
// main.ts
import { Menu, Action, MenuPrompt, openMenuPrompt, LoopAction } from "./menus";
// Set of prompts
let prompts = {
menu_1: new MenuPrompt("Menu 1 - This list is ordinal - What would like to do?", 20, true, [
new Menu("Menu 2", "menu_2"),
new LoopAction("Action", () => console.log("Menu 1 action executed")),
new Action("Back", context => context.last),
new Action("Exit", () => process.exit(0)),
]),
menu_2: new MenuPrompt("Menu 2 - This list is NOT ordinal - What would like to do?", 20, false, [
new Menu("Menu 1", "menu_1"),
new LoopAction("Action", () => console.log("Menu 2 action executed")),
new Action("Back", context => context.last),
new Action("Exit", () => process.exit(0)),
]),
};
// Open the "menu_1" prompt
openMenuPrompt("menu_1", prompts);这是lib文件,它包含类型&打开初始提示符的函数。
// menus.ts
import * as inquirer from "inquirer";
// MAIN FUNCTION
export let openMenuPrompt = async (current: string, prompts: Dict<MenuPrompt>, last?: string): Promise<any> => {
let answer: Answer = (await inquirer.prompt([prompts[current]])).value;
let next = answer.execute({current, last});
if (!next) return;
return await openMenuPrompt(next, prompts, current == next? last : current );
};
// PUBLIC TYPES
export class MenuPrompt {
type = "list";
name = "value";
message: string;
pageSize: number;
choices: Choice[];
constructor(message: string, pageSize: number, isOrdinalList: boolean, choices: Choice[]) {
this.message = message;
this.pageSize = pageSize;
this.choices = choices;
if (isOrdinalList) {
this.choices.forEach((choice, i) => choice.name = `${i + 1}: ${choice.name}`)
}
}
}
export interface Choice {
name: string;
value: Answer;
}
export class Action implements Choice {
name: string;
value: Answer;
constructor(name: string, execute: (context?: MenuContext) => any) {
this.name = name;
this.value = {execute};
}
}
export class LoopAction implements Choice {
name: string;
value: Answer;
constructor(name: string, execute: (context?: MenuContext) => any) {
this.name = name;
this.value = {execute: context => execute(context) ?? context.current};
}
}
export class Menu implements Choice {
name: string;
value: Answer;
constructor(name: string, menuKey: string) {
this.name = name;
this.value = {execute: () => menuKey};
}
}
// INTERNAL TYPES
type Dict<T = any> = {[key: string]: T};
interface Answer {
execute: (context: MenuContext) => any;
}
interface MenuContext {
current: string;
last: string;
}https://stackoverflow.com/questions/61417816
复制相似问题