首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用承诺在循环中调用inquirer.js菜单?

如何使用承诺在循环中调用inquirer.js菜单?
EN

Stack Overflow用户
提问于 2020-04-24 21:35:47
回答 2查看 1.8K关注 0票数 0

我编写了一个简单的Node.js程序,并在inquirer.js的帮助下提供了一个很好的菜单系统。但是,在选择菜单中的选项并完成某些操作后,程序将退出。我需要菜单再次显示,直到我选择退出最后一个选项在菜单中。我想用诺言来做这件事,而不是异步/等待。

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

PROGRAM

代码语言:javascript
复制
"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

代码语言:javascript
复制
? 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

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-10-21 00:30:33

您可以使用async/await语法:

声明您的main函数async,并从inquirer返回的承诺await

代码语言:javascript
复制
const main = async () => {
  for (let count = 0; count < 3; count++) {
    await showMenu()
    .then(answers => {
      [...]
  }
};

您的代码不像您预期的那样工作,因为简而言之,解释器在运行任何回调(从承诺)之前执行同步代码。因此,在解析任何I/O回调之前,同步for循环都会执行。对showMenu()的所有调用都返回异步解析的承诺,这意味着不会输出任何内容,并且直到循环之后才会解释输入。

await函数中编写async阻止成功的同步代码,这似乎就是您要做的事情。

票数 2
EN

Stack Overflow用户

发布于 2022-04-26 02:20:44

使用您的代码作为起点,我黑了我自己的库来显示cli菜单。它去掉了大量的问询者的样板,让你简单地声明一个菜单图/树。

main.ts文件显示了您如何使用它。您可以声明一个MenuPrompts字典,您可以在其中添加菜单、操作和LoopActions。每个提示符都有一个键,其他提示可以路由到该键。

代码语言:javascript
复制
// 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文件,它包含类型&打开初始提示符的函数。

代码语言:javascript
复制
// 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;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61417816

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档