学习Node.js CLI的输入

151 阅读4分钟

Node.js CLI输入

在本教程中,我们将学习如何在Node.js CLI应用程序中获得用户输入。要做到这一点,你需要监听STDIN (标准输入),Node.js将其暴露为process.stdin ,一个可读流。

前提条件

  • 你应该对JavaScript语言有一定的了解。

  • 你应该在你的电脑上安装[Node.js]。

项目设置

为了开始工作,让我们来设置我们的项目。

创建一个名为node-cli-input 的新目录。

在该目录中,运行。

npm init -y

这将生成一个package.json 文件。

一旦完成,创建一个名为index.js 的新文件来编写我们的代码。

Readline包

readline 包是Node.js中的一个内置包。readline 是一个围绕标准I/O的包装器。

让我们把readline 包导入我们的index.js 文件中。

const readline = require('readline');

我们应该使用readline.createInterface() 方法创建一个新的readline 接口对象,并配置可读和可写流。让我们把输入和输出流分别设置为process.stdinprocess.stdout

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

我们可以使用rl.question() 方法向用户提出问题。

rl.question() 方法需要2个参数。

  • 字符串:这个字符串将作为问题显示给用户。

  • 回调函数rl.question() 方法将等待,直到用户提供输入。一旦用户提供输入,这个回调函数将被执行。这个回调函数将得到用户的输入作为参数。

注意:我们应该使用回调函数里面的rl.close() 方法关闭流。如果不关闭,进程将一直处于空闲状态。

比如说

rl.question("Your favorite color? ", (input) => {
  console.log(input);
  rl.close();
});

输出。

Your favorite color? Black
Black

你可以使用rl.on() 方法为close streams 事件添加一个事件监听器。

rl.on('close', () => {
  console.log('Streams Closed')
})

输出。

Your favorite color? Black
Black
Streams Closed

回调地狱

rl.question() 方法的问题是,它没有返回一个[Promise]。因此,我们不能使用[async/await]来暂停程序的流程,直到用户提供输入。

如果你想依次获得多个用户的输入,你必须在一个回调函数中进行,比如这样。

rl.question("Question 1? ", (answer1) => {
  // do stuff

  rl.question("Question 2? ", (answer2) => {
    // do stuff

    rl.question("Question 3? ", (answer3) => {
      // do stuff

      rl.question("Question 4? ", (answer4) => {
        console.log(answer1, answer2, answer3, answer4);
        rl.close();
      });
    });
  });
});

正如你所看到的,这很快就会失去控制,代码将很难管理。

异步迭代器

异步迭代允许我们对异步来的数据进行迭代,按需进行。你可以创建一个异步迭代器,对输入流中的每一行进行迭代。

for await (const line of rl) {
  // Each line in from the input stream will be available successively here as `line`.
}

我们不能在async 函数之外使用await 关键字。因此,我们需要把所有的代码包在一个异步函数里面。

async function main() {
  // do your stuff here

  for await (const line of rl) {
    // Each line in from the input stream will be available here as `line`.
  }
}

main();

让我们创建一个名为input() 的新函数来提示用户并获得输入。

我们可以使用readline 对象的Symbol.asyncIterator来获取输入流中的下一个值。

async function input(prompt) {
  console.log(prompt);
  return (await rl[Symbol.asyncIterator]().next()).value;
}

现在,我们可以使用这个函数从输入流中获取数值,并使用await 关键字来暂停执行,直到我们得到用户的输入。

async function main() {
  const name = await input("May I have your name? ");
  const color = await input("Your favorite color? ");

  console.log(name, color);
  rl.close();
}

main();

Readline同步包

如果你不介意安装一个外部包,这将增加你正在构建的CLI应用程序的包的大小,你可以使用readline-sync 包来以同步的方式获得用户的输入。

让我们通过运行来安装readline-sync

npm install readline-sync

现在,让我们导入该包。

const readlineSync = require("readline-sync");

readline 包类似,你可以使用readlineSync.question() 方法来提示用户输入。

readline 包不同的是,你不需要给这个函数传递一个回调函数。readlineSync.question() 方法将返回用户的输入。

let input = readlineSync.question('May I have your name? ');
console.log(`Hi ${input}!`);

readlineSync 包也有其他函数,如readlineSync.keyInYN(),readlineSync.keyInSelect(), 等。

readlineSync.keyInYN() 是用来获取用户在不按回车键的情况下对单个按键的响应。如果按了**"Y"**,该函数将返回true ,如果按了其他东西,则返回false

if (readlineSync.keyInYN('Yes?')) {
  // 'Y' key was pressed.
} else {
  // Another key was pressed.
}

readlineSync.keyInSelect() 用来提示用户从一个列表中选择一个项目。该函数将返回用户选择的数字。当我们使用这个函数时,用户不需要按回车键

let colors = ['Black', 'White', 'Gray', 'Yellow', 'Blue'];

let index = readlineSync.keyInSelect(colors, 'Favorite Color?');
console.log(colors[index]);

输出。

[1] Black
[2] White
[3] Gray
[4] Yellow
[5] Blue
[0] CANCEL
 
Favorite Color? [1...5 / 0]: 2
White

让我们回顾一下

  1. 我们使用readline 包来提示用户的输入。

  2. 我们为readline流的close 事件添加了一个事件监听器。

  3. 我们使用异步迭代器来编写一个异步函数来获取用户的输入,以防止回调地狱。

  4. 我们使用readline-sync 包来同步提示用户的输入。

恭喜你,🥳你成功了。