Node.js v18.18.2 文档


目录

REPL 交互式编程环境#

稳定性:2 - 稳定

源代码: lib/repl.js

node:repl模块提供了 Read-Eval-Print-Loop (REPL) 实现,它既可以作为独立程序使用,也可以包含在其他应用程序中。可以使用以下方式访问它:

const repl = require('node:repl'); 

设计与特点#

node:repl模块导出repl.REPLServer类。运行时,repl.REPLServer的实例将接受单独的用户输入行,根据用户定义的评估函数评估这些输入,然后输出结果。输入和输出可以分别来自stdinstdout,也可以连接到任何 Node.js

repl.REPLServer的实例支持自动完成输入、完成预览、简单的 Emacs 风格的行编辑、多行输入、 ZSH式的反向 i 搜索、ZSH式的基于子字符串的历史搜索、ANSI-样式输出、保存和恢复当前 REPL 会话状态、错误恢复和可定制的评估功能。不支持 ANSI 样式和 Emacs 样式行编辑的终端会自动回退到有限的功能集。

命令和特殊键#

所有 REPL 实例都支持以下特殊命令:

  • .break:在输入多行表达式的过程中,输入.break命令(或按Ctrl+ C)可中止对该表达式的进一步输入或处理。
  • .clear:将 REPL context重置为空对象并清除输入的任何多行表达式。
  • .exit:关闭 I/O 流,导致 REPL 退出。
  • .help:显示特殊命令的列表。
  • .save:将当前 REPL 会话保存到文件中: > .save ./file/to/save.js
  • .load:将文件加载到当前 REPL 会话中。 > .load ./file/to/load.js
  • .editor:进入编辑器模式(Ctrl+D完成,Ctrl+C取消)。
> .editor
// Entering editor mode (^D to finish, ^C to cancel)
function welcome(name) {
  return `Hello ${name}!`;
}

welcome('Node.js User');

// ^D
'Hello Node.js User!'
> 

REPL 中的以下组合键具有以下特殊效果:

  • Ctrl+ :按下一次时,与.breakC命令具有相同的效果 。在空行上按两次时,与.exit 命令具有相同的效果。
  • Ctrl+ :与.exitD命令具有相同的效果。
  • Tab:当在空行上按下时,显示全局和局部(范围)变量。在输入其他内容时按下该按钮,会显示相关的自动完成选项。

有关与反向 i 搜索相关的键绑定,请参阅reverse-i-search。对于所有其他键绑定,请参阅TTY 键绑定

默认评价#

默认情况下,repl.REPLServer的所有实例都使用评估函数来评估 JavaScript 表达式并提供对 Node.js 内置模块的访问。创建repl.REPLServer实例时,可以通过传入替代评估函数来覆盖此默认行为。

JavaScript 表达式#

默认评估器支持直接评估 JavaScript 表达式:

> 1 + 1
2
> const m = 2
undefined
> m + 1
3 

除非块或函数内另有作用域,否则隐式声明或使用constletvar关键字声明的变量均在全局作用域中声明。

全局和本地范围#

默认计算器提供对全局范围内存在的任何变量的访问。可以通过将变量分配给与每个REPLServer关联的context 对象来显式向 REPL 公开变量:

const repl = require('node:repl');
const msg = 'message';

repl.start('> ').context.m = msg; 

context对象中的属性在 REPL 中显示为本地属性:

$ node repl_test.js
> m
'message' 

默认情况下,上下文属性不是只读的。要指定只读全局变量,必须使用Object.defineProperty()定义上下文属性:

const repl = require('node: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('node:fs')

> fs.createReadStream('./some/file'); 
全局未捕获的异常#

REPL 使用domain模块来捕获该 REPL 会话的所有未捕获的异常。

在 REPL 中使用domain模块会产生以下副作用:

_(下划线)变量的赋值#

默认情况下,默认求值器会将最近计算的表达式的结果分配给特殊变量_(下划线)。显式将_设置为某个值将禁用此行为。

> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Expression assignment to _ now disabled.
4
> 1 + 1
2
> _
4 

同样,_error将引用最后看到的错误(如果有)。显式将_error设置为一个值将禁用此行为。

> throw new Error('foo');
Uncaught Error: foo
> _error.message
'foo' 
await关键字#

在顶层启用对await关键字的支持。

> await Promise.resolve(123)
123
> await Promise.reject(new Error('REPL await'))
Uncaught Error: REPL await
    at REPL2:1:54
> const timeout = util.promisify(setTimeout);
undefined
> const old = Date.now(); await timeout(1000); console.log(Date.now() - old);
1002
undefined 

在 REPL 中使用await关键字的一个已知限制是,它会使constlet 关键字的词法范围无效。

例如:

> const m = await Promise.resolve(123)
undefined
> m
123
> const m = await Promise.resolve(234)
undefined
> m
234 

--no-experimental-repl-await应在 REPL 中禁用顶级等待。

反向搜索#

REPL 支持类似于ZSH 的双向反向搜索。用Ctrl+触发R向后搜索,用Ctrl+S触发向前搜索。

将跳过重复的历史记录条目。

一旦按下任何与反向搜索不对应的键,条目就会被接受。按EscCtrl+可以取消C

更改方向会立即从当前位置开始按预期方向搜索下一个条目。

自定义评估函数#

当创建新的repl.REPLServer时,可以提供自定义评估函数。例如,这可以用于实现完全定制的 REPL 应用程序。

下面说明了一个 REPL 的假设示例,该示例执行将文本从一种语言翻译成另一种语言的操作:

const repl = require('node: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 输出#

默认情况下,repl.REPLServer实例在将输出写入提供的Writable 流(默认情况下为process.stdout )之前,使用 util.inspect()方法格式化输出。默认情况下,showProxy检查选项设置为 true,而colors选项设置为 true,具体取决于 REPL 的useColors选项。

可以在构造时指定useColors布尔选项,以指示默认编写器使用 ANSI 样式代码对util.inspect()方法的输出进行着色 。

如果 REPL 作为独立程序运行,则还可以使用inspect.replDefaults属性从 REPL 内部 更改 REPL 的检查默认值,该属性镜像 util.inspect()中的 defaultOptions

> util.inspect.replDefaults.compact = false;
false
> [1]
[
  1
]
> 

要完全自定义repl.REPLServer实例的输出,请为构造时的writer选项传入一个新函数。例如,以下示例只是将任何输入文本转换为大写:

const repl = require('node: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的实例是使用repl.start()方法或直接使用 JavaScript new关键字创建的。

const repl = require('node:repl');

const options = { useColors: true };

const firstInstance = repl.start(options);
const secondInstance = new repl.REPLServer(options); 

事件:'exit'#

当通过接收.exit命令作为输入、用户按Ctrl+两次以发出SIGINTC信号或按+退出 REPL 时,会发出 'exit' 事件在输入流上发出'end'信号。调用侦听器回调时无需任何参数。CtrlD

replServer.on('exit', () => {
  console.log('Received "exit" event from repl!');
  process.exit();
}); 

事件:'reset'#

当 REPL 的上下文重置时,会发出'reset'事件。每当接收到.clear命令作为输入时,就会发生这种情况,除非REPL 使用默认计算器,并且repl.REPLServer实例是在useGlobal选项设置为true的情况下创建的。 。将使用对context对象的引用作为唯一参数来调用侦听器回调。

这主要用于将 REPL 上下文重新初始化为某些预定义的状态:

const repl = require('node: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)#

replServer.defineCommand()方法用于向 REPL 实例添加新的.前缀命令。通过键入.后跟 keyword来调用此类命令。cmd是具有以下属性的FunctionObject

  • help <string>输入.help时显示的帮助文本(可选)。
  • action <Function>要执行的函数,可以选择接受单个字符串参数。

以下示例显示了添加到 REPL 实例的两个新命令:

const repl = require('node:repl');

const replServer = repl.start({ prompt: '> ' });
replServer.defineCommand('sayhello', {
  help: 'Say hello',
  action(name) {
    this.clearBufferedCommand();
    console.log(`Hello, ${name}!`);
    this.displayPrompt();
  },
});
replServer.defineCommand('saybye', function saybye() {
  console.log('Goodbye!');
  this.close();
}); 

然后可以在 REPL 实例中使用新命令:

> .sayhello Node.js User
Hello, Node.js User!
> .saybye
Goodbye! 

replServer.displayPrompt([preserveCursor])#

replServer.displayPrompt()方法让 REPL 实例准备好接受用户的输入,将配置的prompt打印到output中的新行 并恢复input接受新输入。

当输入多行输入时,会打印省略号而不是“提示”。

preserveCursortrue时,光标位置不会重置为0

replServer.displayPrompt方法主要用于从使用replServer.defineCommand()方法注册的命令的操作函数内调用 。

replServer.clearBufferedCommand()#

replServer.clearBufferedCommand()方法清除所有已缓冲但尚未执行的命令。此方法主要用于从使用replServer.defineCommand()方法注册的命令的操作函数内调用 。

replServer.parseREPLKeyword(keyword[, rest])#

稳定性:0 - 已弃用。

用于解析和执行REPLServer关键字的内部方法。如果keyword是有效关键字,则返回true ,否则返回 false

replServer.setupHistory(historyPath, callback)#

初始化 REPL 实例的历史日志文件。执行 Node.js 二进制文件并使用命令行 REPL 时,默认情况下会初始化历史文件。但是,以编程方式创建 REPL 时情况并非如此。以编程方式使用 REPL 实例时,使用此方法初始化历史日志文件。

repl.builtinModules#

所有 Node.js 模块的名称列表,例如'http'

repl.start([options])#

  • options <对象> | <字符串>
    • prompt <string>要显示的输入提示。默认值: '> ' (尾随空格)。
    • input <stream.Readable>将从中读取 REPL 输入的Readable流。默认值: process.stdin
    • output <stream.Writable> REPL 输出将写入的Writable流。默认值: process.stdout
    • terminal <boolean>如果为true,则指定output应被视为 TTY 终端。 默认值: 实例化时检查output 流上的isTTY 属性的值。
    • eval <Function>评估每个给定输入行时要使用的函数。默认值: JavaScript eval() 函数的异步包装器。eval函数可能会出错并显示repl.Recoverable,指示输入不完整并提示输入其他行。
    • useColors <boolean>如果为true,则指定默认的writer 函数应包含 REPL 输出的 ANSI 颜色样式。如果提供了自定义 writer函数,则此函数无效。默认值:如果 REPL 实例的terminal值为true ,则检查 output 流上的颜色支持。
    • useGlobal <boolean>如果为true,则指定默认评估函数将使用 JavaScript global作为上下文,而不是为 REPL 创建新的单独上下文实例。节点 CLI REPL 将此值设置为true默认值: false
    • ignoreUndefined <boolean>如果为true ,则指定默认编写器在计算结果为undefined时不会输出命令的返回值 。默认值: false
    • writer <Function>在写入output之前调用以格式化每个命令的输出的函数。默认值: util.inspect()
    • completer <Function>用于自定义 Tab 自动完成的可选函数。有关示例,请参阅readline.InterfaceCompleter
    • replMode <symbol>一个标志,指定默认评估器是在严格模式还是默认(宽松)模式下执行所有 JavaScript 命令。可接受的值为:
      • repl.REPL_MODE_SLOPPY以草率模式计算表达式。
      • repl.REPL_MODE_STRICT在严格模式下计算表达式。这相当于在每个 repl 语句前面加上'use strict'
    • breakEvalOnSigint <boolean>当收到SIGINT时(例如按下Ctrl+时),停止评估当前代码段 。它不能与自定义evalC函数一起使用。默认值:false
    • preview <boolean>定义 repl 是否打印自动完成并输出预览。默认值: 使用默认 eval 函数的 true和使用自定义 eval 函数的情况下的false 。如果terminal为假,则没有预览,并且preview的值无效。
  • 返回:<repl.REPLServer>

repl.start()方法创建并启动一个repl.REPLServer实例。

如果options是字符串,则它指定输入提示:

const repl = require('node:repl');

// a Unix style prompt
repl.start('$ '); 

Node.js REPL#

Node.js 本身使用node:repl模块来提供自己的交互界面来执行 JavaScript。可以通过执行 Node.js 二进制文件而不传递任何参数(或通过传递-i参数)来使用它:

$ 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 历史记录。将从值中删除空格。在 Windows 平台上,具有空值的环境变量无效,因此将此变量设置为一个或多个空格以禁用持久 REPL 历史记录。
  • NODE_REPL_HISTORY_SIZE:控制如果历史记录可用,将保留多少行历史记录。必须是正数。 默认值: 1000
  • NODE_REPL_MODE:可能是'sloppy''strict'默认值: 'sloppy',这将允许运行非严格模式代码。

持续的历史#

默认情况下,Node.js REPL 将通过将输入保存到位于用户主目录中的.node_repl_history文件来保留node REPL 会话之间的历史记录。可以通过设置环境变量 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" 

针对单个正在运行的实例启动多个 REPL 实例#

可以针对单个正在运行的 Node.js 实例创建并运行多个 REPL 实例,这些实例共享单个global对象,但具有单独的 I/O 接口。

例如,以下示例在stdin、Unix 套接字和 TCP 套接字上提供单独的 REPL:

const net = require('node:net');
const repl = require('node:repl');
let connections = 0;

repl.start({
  prompt: 'Node.js via stdin> ',
  input: process.stdin,
  output: process.stdout,
});

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via 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 via TCP socket> ',
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(5001); 

从命令行运行此应用程序将在标准输入上启动 REPL。其他 REPL 客户端可以通过 Unix 套接字或 TCP 套接字进行连接。例如,telnet对于连接到 TCP 套接字很有用,而socat可用于连接到 Unix 和 TCP 套接字。

通过从基于 Unix 套接字的服务器而不是 stdin 启动 REPL,可以连接到长时间运行的 Node.js 进程而无需重新启动它。

有关在net.Servernet.Socket实例上运行“全功能”( terminal ) REPL的示例,请参阅: https://gist.github。 com/TooTallNate/2209310

有关通过curl(1)运行 REPL 实例的示例,请参阅: https: //gist.github.com/TooTallNate/2053342

NodeJS中文文档为Read dev Docs平台提供托管,中文NodeJS文档均由英文版NodeJS文档翻译,版权属于nodejs.org