为什么 readlineInterface.question() 运行得很早?

Why is readlineInterface.question() running early?

提问人:MB1721 提问时间:8/26/2023 最后编辑:MB1721 更新时间:8/28/2023 访问量:23

问:

我一直在开发一款名为“秘密消息”的游戏,玩家必须猜测隐藏在目录中多个文本文件中的秘密消息。我的应用程序是一个节点模块,因此我可以使用 Chalk5 ESM。我正在使用 readline 回调 API 来评估用户输入。

我分别使用 和 作为我的 和 初始化了一个 readline 接口。我的问题是,每当我使用该方法时,我的代码似乎在没有输入的情况下运行。每当我使用 Node REPL 时都会发生同样的情况;使用 readline.createInterface 创建新接口后,我在终端中发送的任何文本都会加倍。例如:process.stdinprocess.stdoutinputoutputquestion()

> const rl = require('readline')
// output: undefined
> const channel = rl.createInterface({input: process.stdin, output: process.stdout})
// output: undefined

然后,尝试键入会导致:channel.question( ... )

// This is my real input.
> cchaannnneell..qquueessttiioonn(())

有谁知道这是怎么回事?

以下是实际游戏的相关代码部分:

function getDirParameter(dirParameter, directoryQuery) {
  let userChoice;
  channel.question(directoryQuery, (dirChoice) => {
    userChoice = dirChoice;
    console.log(dirChoice);
    switch(dirChoice) {
      case 'current':
        dirParameter = __dirname;
        break;
      case 'custom':
        console.log('User chose "custom".');
        break; 
      default: 
        console.error('Invalid option.');
        break;
    }
    channel.close();
  });
  
  return userChoice;
}

我尝试在关闭界面之前记录用户输入。终端最终不记录任何内容。

节点.js 回调 读取行

评论

0赞 jfriend00 8/26/2023
您正在运行 BEFORE 完成。 是非阻塞和异步的。它会在完成之前返回。您必须在回调中关闭通道,而不是在回调之后关闭通道。searchParameters.directoryPath = evaluateCustomPath();channel.question()channel.question()
0赞 MB1721 8/28/2023
@jfriend00,我将函数重命名为 ,然后重构了我的代码,以便我调用 .我确保关闭函数内部的通道,但在我向终端输入任何内容之前,代码仍然像有输入一样运行。evaluateCustomPath()getCustomPath()const dirParameter = await getDirParameter(searchParameters.directoryPath, directoryQuery);
0赞 jfriend00 8/28/2023
await不会做任何有用的事情,除非它正在等待异步代码完成时解析的承诺,并且我在此代码中没有看到任何承诺。因此,无论您进行什么重构,听起来都不像是在做任何事情,因此您仍然有问题。await
0赞 MB1721 8/28/2023
我最终完全重写了函数,给我带来了麻烦。我之前将代码放入异步函数中并返回了一个 promise,因此 await 语句背后是有目的的。现在一切都是同步的,代码仍然给我带来麻烦。我重写了原来的帖子,以反映我遇到问题的机会。getCustomPath()getDirParameter()

答:

0赞 jfriend00 8/28/2023 #1

您显示的代码看起来不完整,因为您实际上没有根据语句执行任何不同操作。但是,这是该函数的一个有前途的版本:switch()

async function getDirParameter(channel, dirParameter, directoryQuery) {
    return new Promise((resolve, reject) => {
        channel.question(directoryQuery, (dirChoice) => {
            console.log(dirChoice);
            switch (dirChoice) {
                case 'current':
                    dirParameter = __dirname;
                    break;
                case 'custom':
                    console.log('User chose "custom".');
                    break;
                default:
                    console.error('Invalid option.');
                    break;
            }
            resolve(dirChoice);
        });
    });
}

你可以在这样的函数中使用它:async

const dirChoice = await getDirParameter(channel, dirQuery);

请注意,此版本的函数不会关闭通道,因为打开通道的代码似乎应该是关闭通道的代码,并且此函数可能希望在同一通道上多次使用。这是一个由你决定的设计选择,但这对我来说很有意义,所以我以这种方式进行了重写。

P.S. 分配给函数参数,例如,然后不使用 dirParameter 执行任何其他操作实际上并没有完成任何事情,所以基本上,您的语句没有完成任何事情。也许还有更多代码......dirParameterswtich()

注意:从 nodejs v17 开始,有一个实验性接口已经返回了一个 promise。rl.question()

评论

0赞 MB1721 8/28/2023
所以我的主要解决方法应该是在调用getDirParameter的异步函数内部创建通道?我之前已经全局创建了,所以通道参数在这里是多余的,除非关键是让我在我的调用函数范围内创建它。channelgetDirParameter()
0赞 MB1721 8/28/2023
好吧,有一个全局声明的readline接口似乎是问题所在。谢谢!我希望我有足够的“声誉”来投票给你。
0赞 jfriend00 8/28/2023
@MB1721 - 您可以(在任何声誉级别)通过单击问题左侧的复选标记来接受问题的答案。