readline 内置模块
提供接口,一次一行地读取可读流(例如 process.stdin )中的数据。基本使用:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('your name: ', (answer => {
console.log(answer);
rl.close();
}));
readline 源码解读
强制将函数转为构造函数
if (!(this instanceof Interface)) { return new Interface(input, output, completer, terminal); }获取事件驱动能力
EventEmitter.call(this);监听键盘事件
emitKeypressEvents(input, this); // `input` usually refers to stdin input.on('keypress', onkeypress); input.on('end', ontermend);
readline 核心实现原理

- 核心
emitKeypressEvents(input, this),监听终端中的键盘输入emitKeys()是一个Generator函数
- 出现等待用户输入的核心:
stream.on('data', onData) input.setRawMode(true)参数默认是false表示整行进行监听,变为true表示逐字监听,这时每次按下键盘的输入都必须处理。- 用户在命令行中输入,
_stream_readable.js中addChunk()函数派发事件stream.emit('data', chunk); this.input.pause()将输入流关闭

知识点
Number.isNaN(val)terminal = !!process.stdout.isTTY/!!process.stdin.isTTY判断是否终端
手写 readline 核心实现
function stepRead(callback) {
const input = process.stdin;
const output = process.stdout;
let line = '';
function onKeypress(s) {
output.write(s);
line += s;
switch(s) {
case '\r':
input.pause();
callback(line);
break;
}
}
emitKeypressEvents(input);
input.on('keypress', onKeypress);
input.setRawMode(true);
input.resume();
}
function emitKeypressEvents(stream) {
function onData(chunk) {
g.next(chunk.toString());
}
const g = emitKeys(stream);
g.next(); // 执行到第一个 yield 位置
stream.on('data', onData);
}
function* emitKeys(stream) {
while(true) {
let ch = yield;
stream.emit('keypress', ch);
}
}
stepRead(function(s) {
console.log('answer: ' + s);
});