命令行输入输出
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:在控制台打印进度条