命令行输入输出
process.stdin
process.stdin 属性是 prcess 模块的内置API,用于监听用户输入。它返回一个可读流,通过 on() 注册事件监听器。
Node.js 为可读流提供了不同风格的API用法,以适应开发人员的习惯。
on('data')
收到数据触发回调,并等待下一次输入。
process.stdin.on('data', data => {
console.log(`收到输入 ${data.toString()}`)
})on('readable')
收到数据触发事件,需手动通过.read()读取数据。
process.stdin.on('readable', ()=>{
// 使用循环,保持流不结束。
// 卡死的写法
while ( true ) {
process.stdin.read()
}
// 能用的写法
while ( process.stdin.read() ){ }
})process.stdin.read() 返回Buffer类型数据,只有为空 null 时才会判断为假值。
这个表达式实现为同步用法,但背后是系统层面的IO操作,因此不同的语法结构会表现出明显差异。
上面的卡死写法与能用写法的区别,我理解为:
- 卡死写法:每当
readable事件回调执行时,开始无限循环地向IO操作队列中插入一次IO操作。 - 能用写法:每当
readable事件回调执行时,向IO操作队列中插入一次IO操作,等返回操作结果后开始下一次循环。
从这个例子可见,Node.js 将IO操作实现为同步语法后,配合代码循环语法是有坑的。
Node.js 官网也说 'readable' 事件较难理解,手动处理 'readable' 的意义是提升吞吐量,即提升性能。
In general, the
readable.pipe()and'data'event mechanisms are easier to understand than the'readable'event. However, handling'readable'might result in increased throughput.
pipe()
// 将输入流写入输出流
process.stdin.pipe( process.stdout )pipe() 运行后返回传入的流,在传入的流是双工流(可读写)时,可实现链式调用。
process.stdout 、 process.stderr
process.stdout 返回一个可写流,用于打印输出信息,console.log()内部使用它打印输出;process.stderr 返回一个可写流,用于打印错误信息,console.error()内部使用它打印错误。
两者都支持可写流的属性、方法。
常见用法:将子进程的输出、错误信息打印到控制台
const childProcess = require('child_process')
const cp = childProcess.exec(`node -e "console.log('child_process log');console.error('child_process error')"`)
cp.stdout.pipe(process.stdout)
cp.stderr.pipe(process.stderr)Readline
Readline 是Node.js的内置模块,用于处理可读流类型的实际使用问题,代理基本的 process.stdin、process.stdout 操作,逐行读取。
createInterface
创建实例,配置选项。
const readline = require('node:readline')
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})实例创建后进程不会结束,而是持续处理用户输入,直到调用 rl.close() 结束。
prompt
提示字符串,在 Windows 中默认值是 >
rl.prompt():打印换行+提示字符串rl.setPrompt():设置提示字符串内容rl.getPrompt():获得提示字符串内容
使用提示字符串以便提示进程当前需要用户输入
const readline = require('readline')
const rl = readline.createInterface({ input: process.stdin , output: process.stdout })
rl.prompt() // 提示用户输入
rl.on('line', line=>{
console.log('received:', line)
rl.prompt() // 提示用户输入
})静态方法
未创建实例也可以通过readline调用静态方法
- moveCursor:相对当前光标位置,移动光标
- cursorTo:移动光标到绝对位置
- clearScreenDown:清除光标后的内容
- clearLine:清除光标所在行及之后的内容
第三方库
- prompts:轻量(依赖少)、交互友好的命令行提问
- inquirer:功能丰富的命令行交互工具
- chalk:为命令行输出添加样式,最多用户
- kleur:为命令行输出添加样式,轻量,prompts依赖
- figlet:在控制台打印由符号拼接成的图案字体
- cli-progress:在控制台打印进度条