- assert - 断言
- Buffer - 缓冲器
- child_process - 子进程
- cluster - 集群
- console - 控制台
- crypto - 加密
- dgram - 数据报
- dns - 域名服务器
- Error - 异常
- events - 事件
- fs - 文件系统
- global - 全局变量
- http - HTTP
- https - HTTPS
- module - 模块
- net - 网络
- os - 操作系统
- path - 路径
- process - 进程
- querystring - 查询字符串
- readline - 逐行读取
- repl - 交互式解释器
- stream - 流
- string_decoder - 字符串解码器
- timer - 定时器
- tls - 安全传输层
- tty - 终端
- url - 网址
- util - 实用工具
- v8 - V8引擎
- vm - 虚拟机
- zlib - 压缩
Node.js v10.8.0 文档
repl (交互式解释器)#
repl
模块提供了一种“读取-求值-输出”循环(REPL)的实现,它可作为一个独立的程序或嵌入到其他应用中。
可以通过以下方式使用它:
const repl = require('repl');
设计与特性#
repl
模块导出了 repl.REPLServer
类。
当 repl.REPLServer
实例运行时,它接收用户输入的每一行,根据用户定义的解释函数解释这些输入,然后输出结果。
输入可以是 stdin
,输出可以是 stdout
,或者也可以连接到其他任何 Node.js 流。
repl.REPLServer
实例支持输入的自动补全、精简 Emacs 风格的行编辑、多行输入、ANSI 风格的输出、当前 REPL 会话状态的保存与恢复、错误校正、以及可定制的解释函数。
命令与特殊键#
所有 REPL 的实例都支持下列特殊命令:
.break
- 在输入一个多行表达式的过程中,输入.break
命令(或按下<ctrl>-C
组合键)将终止表达式的继续输入。.clear
- 重置 REPL 的context
为一个空对象,并清除当前正输入的所有多行表达式。.exit
- 关闭输入输出流,退出 REPL。.help
- 显示特定命令的帮助列表。.save
- 保存当前 REPL 会话到一个文件:> .save ./file/to/save.js
.load
- 读取一个文件到当前 REPL 会话。> .load ./file/to/load.js
.editor
进入编辑模式(<ctrl>-D
完成,<ctrl>-C
取消)
> .editor
// 进入编辑模式(^D 完成,^C 取消)
function welcome(name) {
return `你好 ${name}!`;
}
welcome('Node.js 用户');
// ^D
'你好 Node.js 用户!'
>
REPL 中下列按键组合有特殊作用:
<ctrl>-C
- 当按下一次时,与.break
命令的效果一样。当在空白行按下两次时,与.exit
命令的效果一样。<ctrl>-D
- 与.exit
命令的效果一样。<tab>
- 当在空白行按下时,显示全局和本地作用域内的变量。当在输入时按下,显示相关的自动补全选项。
默认的解释器#
默认情况下,所有 repl.REPLServer
实例使用了一个解释函数,它可以解释 JavaScript 表达式、提供对 Node.js 内置模块的访问。
当 repl.REPLServer
实例被创建时可以传入一个替换的解释函数,覆盖其默认的功能。
JavaScript 表达式#
默认的解释器支持直接解释 JavaScript 表达式:
> 1 + 1
2
> const m = 2
undefined
> m + 1
3
除非在块级作用域中或函数中,否则变量不管是隐式地声明还是使用 const
、 let
或 var
关键字声明,都是声明在全局作用域中。
全局作用域与局部作用域#
默认的解释器提供了获取存在于全局作用域中的任何变量的途径。
可以通过给每个 REPLServer
绑定的 context
对象指定变量,来显式地把变量暴露给 REPL。
例如:
const repl = require('repl');
const msg = 'message';
repl.start('> ').context.m = msg;
context
对象的属性表现为 REPL 中的局部变量:
$ node repl_test.js
> m
'message'
默认情况下 context
的属性不是只读的。
要指定只读的全局变量,context
的属性必须使用 Object.defineProperty()
来定义:
const repl = require('repl');
const msg = 'message';
const r = repl.start('> ');
Object.defineProperty(r.context, 'm', {
configurable: false,
enumerable: true,
value: msg
});
访问 Node.js 核心模块#
默认的解释器会自动加载被调用的 Node.js 核心模块到 REPL 环境中。
例如,除非被声明为一个全局变量或一个有限范围的变量,否则输入 fs
会被解释为 global.fs = require('fs')
。
> fs.createReadStream('./some/file');
Global Uncaught Exceptions#
The REPL uses the domain
module to catch all uncaught exceptions for that
REPL session.
This use of the domain
module in the REPL has these side effects:
- Uncaught exceptions do not emit the
'uncaughtException'
event. - Trying to use
process.setUncaughtExceptionCaptureCallback()
throws anERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE
error.
_
(下划线)变量的赋值#
默认的解释器会把最近一次解释的表达式的结果赋值给变量 _
(下划线)。
显式地设置 _
为某个值能禁用该特性。
> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Expression assignment to _ now disabled.
4
> 1 + 1
2
> _
4
`await` keyword#
With the --experimental-repl-await
command line option specified,
experimental support for the await
keyword is enabled.
> await Promise.resolve(123)
123
> await Promise.reject(new Error('REPL await'))
Error: REPL await
at repl:1:45
> const timeout = util.promisify(setTimeout);
undefined
> const old = Date.now(); await timeout(1000); console.log(Date.now() - old);
1002
undefined
自定义的解释函数#
当创建一个新的 repl.REPLServer
时,可以提供一个自定义的解释函数。
这可以用于实现完全定制化的 REPL 应用。
例子,一个执行文本翻译的 REPL:
const repl = require('repl');
const { Translator } = require('translator');
const myTranslator = new Translator('en', 'fr');
function myEval(cmd, context, filename, callback) {
callback(null, myTranslator.translate(cmd));
}
repl.start({ prompt: '> ', eval: myEval });
可恢复的错误#
当用户正在 REPL 中输入时,按下 <enter>
键会把当前行的输入发送到 eval
函数。
为了支持多行输入,eval
函数可以返回一个 repl.Recoverable
实例给提供的回调函数:
function myEval(cmd, context, filename, callback) {
let result;
try {
result = vm.runInThisContext(cmd);
} catch (e) {
if (isRecoverableError(e)) {
return callback(new repl.Recoverable(e));
}
}
callback(null, result);
}
function isRecoverableError(error) {
if (error.name === 'SyntaxError') {
return /^(Unexpected end of input|Unexpected token)/.test(error.message);
}
return false;
}
自定义 REPL 输出#
默认情况下,在把输出写入到提供的可写流(默认为 process.stdout
)之前,repl.REPLServer
实例会使用 util.inspect()
方法对输出进行格式化。
使用 util.inspect()
方法时,useColors
选项可被指定是否在建立默认输出器时使用 ANSI 风格的代码给输出上色。
在构造时,通过在 writer
选项传入一个新的函数,可以完全地自定义一个 repl.REPLServer
实例的输出。
例子,把输入的任何文本转换为大写:
const repl = require('repl');
const r = repl.start({ prompt: '> ', eval: myEval, writer: myWriter });
function myEval(cmd, context, filename, callback) {
callback(null, cmd);
}
function myWriter(output) {
return output.toUpperCase();
}
REPLServer 类#
repl.REPLServer
类继承自 readline.Interface
类。
repl.REPLServer
的实例由 repl.start()
方法创建,不能直接使用 JavaScript 的 new
关键字创建。
'exit' 事件#
当接收到 .exit
命令、或按下两次 <ctrl>-C
发出 SIGINT
信号、或按下 <ctrl>-D
发出 'end'
信号而使 REPL 被退出时,触发 'exit'
事件。
监听器的回调函数被调用时不带任何参数。
replServer.on('exit', () => {
console.log('从 REPL 接收到 "exit" 事件!');
process.exit();
});
'reset' 事件#
当 REPL 的上下文被重置时,触发 'reset'
事件。
每当接收到 .clear
命令时会触发该事件,除非 REPL 正在使用默认的解释器并且 repl.REPLServer
实例被创建时 useGlobal
选项被设为 true
。
监听器的回调函数被调用时会带上 context
对象作为惟一的参数。
这主要被用于重新初始化 REPL 上下文,使之达到某些预定义的状态,如下面的例子:
const repl = require('repl');
function initializeContext(context) {
context.m = 'test';
}
const r = repl.start({ prompt: '> ' });
initializeContext(r.context);
r.on('reset', initializeContext);
当代码被执行时,全局的 'm'
变量可以被修改,但随后的 .clear
命令会把它重置回初始值:
$ ./node example.js
> m
'test'
> m = 1
1
> m
1
> .clear
Clearing context...
> m
'test'
>
replServer.defineCommand(keyword, cmd)#
keyword
<string> 命令关键字(开头不带.
字符)。cmd
<Object> | <Function> 当命令被执行时调用的函数。
replServer.defineCommand()
方法用于添加新的前缀为 .
的命令到 REPL 实例。
这些命令通过输入一个 .
加 keyword
来调用。
cmd
可以是一个函数或一个具有以下属性的对象:
help
<string> 当键入.help
时显示的帮助说明(可选)。action
<Function> 要执行的函数,可接受一个字符串参数。
例子,添加两个新命令到 REPL 实例:
const repl = require('repl');
const replServer = repl.start({ prompt: '> ' });
replServer.defineCommand('sayhello', {
help: '打招呼',
action(name) {
this.lineParser.reset();
this.bufferedCommand = '';
console.log(`你好,${name}!`);
this.displayPrompt();
}
});
replServer.defineCommand('saybye', function saybye() {
console.log('再见!');
this.close();
});
在 REPL 实例中使用新的命令:
> .sayhello Node.js中文网
你好,Node.js中文网!
> .saybye
再见!
replServer.displayPrompt([preserveCursor])#
preserveCursor
<boolean>
replServer.displayPrompt()
方法会让 REPL 实例做好用户输入的准备,打印配置的 prompt
到 output
中新的一行,然后返回 input
等待新的输入。
当正在键入多行输入时,会打印省略号而不是提示符。
当 preserveCursor
为 true
时,游标位置不会被复位到 0
。
replServer.displayPrompt
方法主要被使用 replServer.defineCommand()
方法注册的命令的 action
函数调用。
replServer.clearBufferedCommand()#
The replServer.clearBufferedCommand()
method clears any command that has been
buffered but not yet executed. This method is primarily intended to be
called from within the action function for commands registered using the
replServer.defineCommand()
method.
replServer.parseREPLKeyword(keyword, [rest])#
keyword
<string> the potential keyword to parse and executerest
<any> any parameters to the keyword command- Returns: <boolean>
An internal method used to parse and execute REPLServer
keywords.
Returns true
if keyword
is a valid keyword, otherwise false
.
repl.start([options])#
-
prompt
<string> 要显示的输入提示符。默认为>
(末尾有一个空格)。input
<stream.Readable> REPL 输入要被读取的可读流。默认为process.stdin
。output
<stream.Writable> REPL 输出要被写入的可写流。默认为process.stdout
。terminal
<boolean> 如果为true
,则指定output
应被当作一个 TTY 终端,并且可以使用 ANSI/VT100 转义码写入。 默认值为初始化时output
流的isTTY
属性的值。eval
<Function> 当解释每行输入时使用的函数。默认为 JavaScripteval()
函数的异步封装。eval
函数出错时会返回repl.Recoverable
,表明输入不完整并提示用户完成输入。useColors
<boolean> 如果为true
,则指定默认的writer
函数可以在 REPL 输出中包含 ANSI 颜色风格。 如果提供了自定义的writer
函数,则该参数无效。 默认为 REPL 实例的terminal
属性的值。useGlobal
<boolean> 如果为true
,则指定默认的解释函数使用 JavaScriptglobal
作为上下文,而不是为 REPL 实例创建一个新的独立的上下文。 在node命令行(node CLI)交互解释器中,这个值为true
. 默认为false
。ignoreUndefined
<boolean> 如果为true
,则指定默认的输出器不会输出命令返回的undefined
值。 默认为false
。writer
<Function> 在写入到output
之前,该函数被调用用来格式化每个命令的输出。 默认为util.inspect()
。completer
<Function> 可选的函数,用来自定义 Tab 键的自动补全。 详见readline.InterfaceCompleter
。-
replMode
<symbol> 一个标志位,指定默认的解释器使用严格模式或默认(sloppy)模式来执行 JavaScript 命令。 可选的值有repl.REPL_MODE_SLOPPY
- 使用默认模式解释表达式。repl.REPL_MODE_STRICT
- 使用严格模式解释表达式。该模式等同于在每个 repl 声明前加上'use strict'
。repl.REPL_MODE_MAGIC
- This value is deprecated, since enhanced spec compliance in V8 has rendered magic mode unnecessary. It is now equivalent torepl.REPL_MODE_SLOPPY
(documented above).
breakEvalOnSigint
- 当接收到SIGINT
时停止解释当前代码,比如按下Ctrl+C
。 不能与自定义的eval
函数同时使用。 默认为false
。
repl.start()
方法创建并启动一个 repl.REPLServer
实例。
如果 options
是一个字符串,则它指定了输入提示符:
const repl = require('repl');
// 一个 Unix 风格的提示符
repl.start('$ ');
Node.js 的 REPL#
Node.js 自身也使用 repl
模块为执行 JavaScript 代码提供交互接口。
可以通过不带任何参数(或使用 -i
参数)地执行 Node.js 二进制文件来使用它:
$ node
> const a = [1, 2, 3];
undefined
> a
[ 1, 2, 3 ]
> a.forEach((v) => {
... console.log(v);
... });
1
2
3
环境变量选项#
使用以下环境变量,可以自定义 Node.js REPL 的各种行为:
NODE_REPL_HISTORY
- 当给定了一个有效的路径,则 REPL 的历史记录将被保存到指定的文件,而不是用户目录下的.node_repl_history
文件。 设为""
将禁用 REPL 历史记录。 值两头的空格键会被去掉。NODE_REPL_HISTORY_SIZE
- 默认为1000
。控制历史记录的最大行数。必须是正数。NODE_REPL_MODE
- 可以是sloppy
、strict
或magic
。 默认是sloppy
, 在sloppy
模式下,允许代码在非严格模式下运行.magic
模式已经被弃用,且被视为sloppy
模式运行.
历史记录#
默认情况下,Node.js REPL 模块会把 node
REPL 会话之间的历史记录保存到用户目录中的 .node_repl_history
文件。
修改环境变量 NODE_REPL_HISTORY=""
可以禁用该功能。
在高级的行编辑器中使用 Node.js REPL#
对于高级的行编辑器,可以使用环境变量 NODE_NO_READLINE=1
来启动 Node.js。
这会以标准的终端配置来启动主 REPL 和调试 REPL,可以使用 rlwrap
。
例如,可以在 .bashrc
文件中添加:
alias node="env NODE_NO_READLINE=1 rlwrap node"
在一个 Node.js 实例中启动多个 REPL 实例#
可以在一个 Node.js 实例中创建并运行多个 REPL 实例,它们共享一个 global
对象但有独立的 I/O 接口。
例子,在 stdin
、Unix socket、和 TCP socket 上分别提供了独立的 REPL:
const net = require('net');
const repl = require('repl');
let connections = 0;
repl.start({
prompt: 'Node.js 使用 stdin> ',
input: process.stdin,
output: process.stdout
});
net.createServer((socket) => {
connections += 1;
repl.start({
prompt: 'Node.js 使用 Unix socket> ',
input: socket,
output: socket
}).on('exit', () => {
socket.end();
});
}).listen('/tmp/node-repl-sock');
net.createServer((socket) => {
connections += 1;
repl.start({
prompt: 'Node.js 使用 TCP socket> ',
input: socket,
output: socket
}).on('exit', () => {
socket.end();
});
}).listen(5001);
从命令行运行这个应用会在 stdin 上启动一个 REPL。
其他 REPL 客户端可以通过 Unix socket 或 TCP socket 进行连接。
例如,可以使用 telnet
连接到 TCP socket,使用 socat
连接到 Unix socket 或 TCP socket。
通过从一个基于 Unix socket 的服务器(而不是 stdin)启动一个 REPL,可以连接到一个长期运行的 Node.js 进程而无需重启它。
例子,在一个 net.Server
实例和一个 net.Socket
实例上运行一个全特性的(terminal
)REPL,详见:https://gist.github.com/2209310
例子,在 curl(1)
上运行一个 REPL 实例,详见:https://gist.github.com/2053342