Node.js v22.22.0 文档


REPL#>

源代码: lib/repl.js

node:repl 模块提供了一个读-求值-打印循环(REPL)实现,可作为独立程序使用,也可以包含在其他应用中。可以通过以下方式访问它:

【The node:repl module provides a Read-Eval-Print-Loop (REPL) implementation that is available both as a standalone program or includible in other applications. It can be accessed using:】

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

设计和特点#>

【Design and features】

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

【The node:repl module exports the repl.REPLServer class. While running, instances of repl.REPLServer will accept individual lines of user input, evaluate those according to a user-defined evaluation function, then output the result. Input and output may be from stdin and stdout, respectively, or may be connected to any Node.js stream.】

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

【Instances of repl.REPLServer support automatic completion of inputs, completion preview, simplistic Emacs-style line editing, multi-line inputs, ZSH-like reverse-i-search, ZSH-like substring-based history search, ANSI-styled output, saving and restoring current REPL session state, error recovery, and customizable evaluation functions. Terminals that do not support ANSI styles and Emacs-style line editing automatically fall back to a limited feature set.】

命令和特殊键#>

【Commands and special keys】

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

【The following special commands are supported by all REPL instances:】

  • .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 中的以下组合键具有这些特殊效果:

【The following key combinations in the REPL have these special effects:】

  • Ctrl+C:按一次时,效果与 .break 命令相同。 在空行上按两次时,效果与 .exit 命令相同。
  • Ctrl+D:效果与.exit命令相同。
  • Tab:在空行上按下时,显示全局和局部(作用域)变量。在输入其他内容时按下,显示相关的自动补齐选项。

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

【For key bindings related to the reverse-i-search, see reverse-i-search. For all other key bindings, see TTY keybindings.】

默认评估#>

【Default evaluation】

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

【By default, all instances of repl.REPLServer use an evaluation function that evaluates JavaScript expressions and provides access to Node.js built-in modules. This default behavior can be overridden by passing in an alternative evaluation function when the repl.REPLServer instance is created.】

JavaScript 表达式#>

【JavaScript expressions】

默认的求值器支持 JavaScript 表达式的直接求值:

【The default evaluator supports direct evaluation of JavaScript expressions:】

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

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

【Unless otherwise scoped within blocks or functions, variables declared either implicitly or using the const, let, or var keywords are declared at the global scope.】

全局和本地作用域#>

【Global and local scope】

默认评估器可以访问全局作用域中存在的任何变量。可以通过将变量分配给与每个 REPLServer 关联的 context 对象,显式地将变量暴露给 REPL:

【The default evaluator provides access to any variables that exist in the global scope. It is possible to expose a variable to the REPL explicitly by assigning it to the context object associated with each REPLServer:】

import repl from 'node:repl';
const msg = 'message';

repl.start('> ').context.m = msg;const repl = require('node:repl');
const msg = 'message';

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

context 对象中的属性在 REPL 中表现为本地属性:

【Properties in the context object appear as local within the REPL:】

$ node repl_test.js
> m
'message' 

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

【Context properties are not read-only by default. To specify read-only globals, context properties must be defined using Object.defineProperty():】

import repl from 'node:repl';
const msg = 'message';

const r = repl.start('> ');
Object.defineProperty(r.context, 'm', {
  configurable: false,
  enumerable: true,
  value: msg,
});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 模块#>

【Accessing core Node.js modules】

默认的求值器在使用时会自动将 Node.js 核心模块加载到 REPL 环境中。例如,除非另行声明为全局变量或作用域变量,否则输入 fs 将按需求值为 global.fs = require('node:fs')

【The default evaluator will automatically load Node.js core modules into the REPL environment when used. For instance, unless otherwise declared as a global or scoped variable, the input fs will be evaluated on-demand as global.fs = require('node:fs').】

> fs.createReadStream('./some/file'); 

全局未捕获异常#>

【Global uncaught exceptions】

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

【The REPL uses the domain module to catch all uncaught exceptions for that REPL session.】

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

【This use of the domain module in the REPL has these side effects:】

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

【Assignment of the _ (underscore) variable】

默认评估器会将最近评估的表达式结果默认赋值给特殊变量 _(下划线)。显式将 _ 设置为某个值将会禁用此行为。

【The default evaluator will, by default, assign the result of the most recently evaluated expression to the special variable _ (underscore). Explicitly setting _ to a value will disable this behavior.】

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

同样地,_error 将指代最后一次出现的错误(如果有的话)。显式地将 _error 设置为某个值将会禁用此行为。

【Similarly, _error will refer to the last seen error, if there was any. Explicitly setting _error to a value will disable this behavior.】

> throw new Error('foo');
Uncaught Error: foo
> _error.message
'foo' 

await 关键字#>

await keyword】

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

【Support for the await keyword is enabled at the top level.】

> 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 关键字的一个已知限制是,它会使 const 关键字的词法作用域失效。

【One known limitation of using the await keyword in the REPL is that it will invalidate the lexical scoping of the const keywords.】

例如:

【For example:】

> const m = await Promise.resolve(123)
undefined
> m
123
> m = await Promise.resolve(234)
234
// redeclaring the constant does error
> const m = await Promise.resolve(345)
Uncaught SyntaxError: Identifier 'm' has already been declared 

--no-experimental-repl-await 应在 REPL 中禁用顶层 await。

反向搜索#>

【Reverse-i-search】

REPL 支持类似于 ZSH 的双向反向-i-搜索。可以通过 Ctrl+R 向后搜索, Ctrl+S 向前搜索。

重复的历史条目将被跳过。

【Duplicated history entries will be skipped.】

只要按下的任意键与反向搜索不对应,就会接受输入。按 EscCtrl+C即可取消。

改变方向会立即从当前位置开始,在预期的方向上搜索下一个条目。

【Changing the direction immediately searches for the next entry in the expected direction from the current position on.】

自定义评估函数#>

【Custom evaluation functions】

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

【When a new repl.REPLServer is created, a custom evaluation function may be provided. This can be used, for instance, to implement fully customized REPL applications.】

执行函数接受以下四个参数:

【An evaluation function accepts the following four arguments:】

  • code <string> 要执行的代码(例如 1 + 1)。
  • context <Object> 代码执行的上下文。这可以是 JavaScript 的 global 上下文,也可以是特定于 REPL 实例的上下文,这取决于 useGlobal 选项。
  • replResourceName <string> 与当前代码评估相关的 REPL 资源的标识符。这对于调试可能很有用。
  • callback <Function> 代码评估完成后调用的函数。回调函数接受两个参数:
    • 如果在评估过程中发生错误,则提供一个错误对象;如果没有发生错误,则为 nullundefined
    • 代码评估的结果(如果提供了错误,则此结果不相关)。

下面示例演示了一个 REPL,它可以对给定的数字进行平方计算,如果提供的输入实际上不是数字,则会打印错误信息:

【The following illustrates an example of a REPL that squares a given number, an error is instead printed if the provided input is not actually a number:】

import repl from 'node:repl';

function byThePowerOfTwo(number) {
  return number * number;
}

function myEval(code, context, replResourceName, callback) {
  if (isNaN(code)) {
    callback(new Error(`${code.trim()} is not a number`));
  } else {
    callback(null, byThePowerOfTwo(code));
  }
}

repl.start({ prompt: 'Enter a number: ', eval: myEval });const repl = require('node:repl');

function byThePowerOfTwo(number) {
  return number * number;
}

function myEval(code, context, replResourceName, callback) {
  if (isNaN(code)) {
    callback(new Error(`${code.trim()} is not a number`));
  } else {
    callback(null, byThePowerOfTwo(code));
  }
}

repl.start({ prompt: 'Enter a number: ', eval: myEval });

可恢复的错误#>

【Recoverable errors】

在 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 输出#>

【Customizing REPL output】

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

【By default, repl.REPLServer instances format output using the util.inspect() method before writing the output to the provided Writable stream (process.stdout by default). The showProxy inspection option is set to true by default and the colors option is set to true depending on the REPL's useColors option.】

useColors 布尔选项可以在构造时指定,用于指示默认的写入器使用 ANSI 样式代码为 util.inspect() 方法的输出添加颜色。

【The useColors boolean option can be specified at construction to instruct the default writer to use ANSI style codes to colorize the output from the util.inspect() method.】

如果 REPL 作为独立程序运行,也可以通过在 REPL 内使用 inspect.replDefaults 属性来更改 REPL 的 检查默认值,该属性反映了来自 util.inspect()defaultOptions

【If the REPL is run as standalone program, it is also possible to change the REPL's inspection defaults from inside the REPL by using the inspect.replDefaults property which mirrors the defaultOptions from util.inspect().】

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

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

【To fully customize the output of a repl.REPLServer instance pass in a new function for the writer option on construction. The following example, for instance, simply converts any input text to upper case:】

import repl from '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();
}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#>

【Class: REPLServer

可以使用 repl.start() 方法创建 repl.REPLServer 的实例,或者直接使用 JavaScript 的 new 关键字。

【Instances of repl.REPLServer are created using the repl.start() method or directly using the JavaScript new keyword.】

import repl from 'node:repl';

const options = { useColors: true };

const firstInstance = repl.start(options);
const secondInstance = new repl.REPLServer(options);const repl = require('node:repl');

const options = { useColors: true };

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

事件:'exit'#>

【Event: 'exit'

'exit' 事件在 REPL 被退出时触发,原因可能是输入 .exit 命令、用户按两次 Ctrl+C 发出 SIGINT 信号,或按 Ctrl+D 在输入流上发出 'end' 信号。监听器回调被调用时不带任何参数。

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

事件:'reset'#>

【Event: 'reset'

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

【The 'reset' event is emitted when the REPL's context is reset. This occurs whenever the .clear command is received as input unless the REPL is using the default evaluator and the repl.REPLServer instance was created with the useGlobal option set to true. The listener callback will be called with a reference to the context object as the only argument.】

这主要可以用于将 REPL 上下文重新初始化到某个预定义状态:

【This can be used primarily to re-initialize REPL context to some pre-defined state:】

import repl from 'node:repl';

function initializeContext(context) {
  context.m = 'test';
}

const r = repl.start({ prompt: '> ' });
initializeContext(r.context);

r.on('reset', initializeContext);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 命令将其重置为初始值:

【When this code is executed, the global 'm' variable can be modified but then reset to its initial value using the .clear command:】

$ ./node example.js
> m
'test'
> m = 1
1
> m
1
> .clear
Clearing context...
> m
'test'
> 

replServer.defineCommand(keyword, cmd)#>

replServer.defineCommand() 方法用于向 REPL 实例添加新的以 . 开头的命令。这类命令通过输入 . 加上 keyword 来调用。cmd 可以是一个 Function 或一个具有以下属性的 Object

【The replServer.defineCommand() method is used to add new .-prefixed commands to the REPL instance. Such commands are invoked by typing a . followed by the keyword. The cmd is either a Function or an Object with the following properties:】

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

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

【The following example shows two new commands added to the REPL instance:】

import repl from '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();
});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 实例中使用新命令:

【The new commands can then be used from within the REPL instance:】

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

replServer.displayPrompt([preserveCursor])#>

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

【The replServer.displayPrompt() method readies the REPL instance for input from the user, printing the configured prompt to a new line in the output and resuming the input to accept new input.】

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

【When multi-line input is being entered, an ellipsis is printed rather than the 'prompt'.】

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

【When preserveCursor is true, the cursor placement will not be reset to 0.】

replServer.displayPrompt 方法主要用于在通过 replServer.defineCommand() 方法注册的命令的操作函数中调用。

【The replServer.displayPrompt method is primarily intended to be called from within the action function for commands registered using the replServer.defineCommand() method.】

replServer.clearBufferedCommand()#>

replServer.clearBufferedCommand() 方法会清除任何已缓冲但尚未执行的命令。该方法主要用于在使用 replServer.defineCommand() 方法注册的命令的操作函数中调用。

【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.setupHistory(historyPath, callback)#>

为 REPL 实例初始化历史记录日志文件。当执行 Node.js 可执行文件并使用命令行 REPL 时,会默认初始化历史文件。但是,当以编程方式创建 REPL 时,情况并非如此。在以编程方式使用 REPL 实例时,请使用此方法初始化历史记录日志文件。

【Initializes a history log file for the REPL instance. When executing the Node.js binary and using the command-line REPL, a history file is initialized by default. However, this is not the case when creating a REPL programmatically. Use this method to initialize a history log file when working with REPL instances programmatically.】

repl.builtinModules#>

稳定性: 0 - 已弃用。请改用 module.builtinModules

一些 Node.js 模块名称的列表,例如 'http'

【A list of the names of some Node.js modules, e.g., 'http'.】

repl.start([options])#>

  • options <Object> | <string>
    • 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 实例创建一个新的独立上下文。Node 命令行 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+C )时停止执行当前代码片段。 不能与自定义 eval 函数同时使用。 默认值: false
    • preview <boolean> 定义 repl 是否打印自动补齐和输出预览。默认值: 使用默认 eval 函数时为 true,如果使用自定义 eval 函数则为 false。如果 terminal 为假值,则不会有预览,preview 的值也不会生效。
  • 返回值:<repl.REPLServer>

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

【The repl.start() method creates and starts a repl.REPLServer instance.】

如果 options 是一个字符串,那么它指定了输入提示:

【If options is a string, then it specifies the input prompt:】

import repl from 'node:repl';

// a Unix style prompt
repl.start('$ ');const repl = require('node:repl');

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

Node.js REPL#>

【The Node.js REPL】

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

【Node.js itself uses the node:repl module to provide its own interactive interface for executing JavaScript. This can be used by executing the Node.js binary without passing any arguments (or by passing the -i argument):】

$ node
> const a = [1, 2, 3];
undefined
> a
[ 1, 2, 3 ]
> a.forEach((v) => {
...   console.log(v);
...   });
1
2
3 

环境变量选项#>

【Environment variable options】

Node.js REPL 的各种行为可以通过以下环境变量进行自定义:

【Various behaviors of the Node.js REPL can be customized using the following environment variables:】

  • NODE_REPL_HISTORY:当给定有效路径时,持久化 REPL 历史记录将保存到指定文件,而不是用户主目录下的 .node_repl_history。将此值设置为 ''(空字符串)将禁用持久化 REPL 历史记录。值的前后空白将被去掉。在 Windows 平台上,环境变量为空值是无效的,因此可以将此变量设置为一个或多个空格以禁用持久化 REPL 历史记录。
  • NODE_REPL_HISTORY_SIZE:控制如果有可用的历史记录,将保存多少行历史记录。必须是正数。默认值: 1000
  • NODE_REPL_MODE:可以是 'sloppy''strict'默认值: 'sloppy',允许运行非严格模式的代码。

持久的历史记录#>

【Persistent history】

默认情况下,Node.js REPL 会在 node REPL 会话之间保持历史记录,通过将输入保存到位于用户主目录的 .node_repl_history 文件中来实现。可以通过设置环境变量 NODE_REPL_HISTORY='' 来禁用此功能。

【By default, the Node.js REPL will persist history between node REPL sessions by saving inputs to a .node_repl_history file located in the user's home directory. This can be disabled by setting the environment variable NODE_REPL_HISTORY=''.】

将 Node.js REPL 与高级行编辑器一起使用#>

【Using the Node.js REPL with advanced line-editors】

对于高级行编辑器,请使用环境变量 NODE_NO_READLINE=1 启动 Node.js。这将使主 REPL 和调试器 REPL 在标准终端设置下启动,从而可以与 rlwrap 一起使用。

【For advanced line-editors, start Node.js with the environment variable NODE_NO_READLINE=1. This will start the main and debugger REPL in canonical terminal settings, which will allow use with rlwrap.】

例如,可以将以下内容添加到 .bashrc 文件中:

【For example, the following can be added to a .bashrc file:】

alias node="env NODE_NO_READLINE=1 rlwrap node" 

在同一进程中启动多个 REPL 实例#>

【Starting multiple REPL instances in the same process】

可以针对单个正在运行的 Node.js 实例创建并运行多个 REPL 实例,这些实例共享一个 global 对象(通过将 useGlobal 选项设置为 true),但具有独立的 I/O 接口。

【It is possible to create and run multiple REPL instances against a single running instance of Node.js that share a single global object (by setting the useGlobal option to true) but have separate I/O interfaces.】

例如,下面的示例在 stdin、Unix 套接字和 TCP 套接字上提供了独立的 REPL,但都共享相同的 global 对象:

【The following example, for instance, provides separate REPLs on stdin, a Unix socket, and a TCP socket, all sharing the same global object:】

import net from 'node:net';
import repl from 'node:repl';
import process from 'node:process';
import fs from 'node:fs';

let connections = 0;

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

const unixSocketPath = '/tmp/node-repl-sock';

// If the socket file already exists let's remove it
fs.rmSync(unixSocketPath, { force: true });

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via Unix socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(unixSocketPath);

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via TCP socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(5001);const net = require('node:net');
const repl = require('node:repl');
const fs = require('node:fs');

let connections = 0;

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

const unixSocketPath = '/tmp/node-repl-sock';

// If the socket file already exists let's remove it
fs.rmSync(unixSocketPath, { force: true });

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via Unix socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(unixSocketPath);

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via TCP socket> ',
    useGlobal: true,
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(5001);

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

【Running this application from the command line will start a REPL on stdin. Other REPL clients may connect through the Unix socket or TCP socket. telnet, for instance, is useful for connecting to TCP sockets, while socat can be used to connect to both Unix and TCP sockets.】

通过从基于 Unix 套接字的服务器而不是标准输入启动 REPL,可以在不中断的情况下连接到一个长期运行的 Node.js 进程。

【By starting a REPL from a Unix socket-based server instead of stdin, it is possible to connect to a long-running Node.js process without restarting it.】

示例#>

【Examples】

基于 net.Servernet.Socket 的全功能“终端”REPL#>

【Full-featured "terminal" REPL over net.Server and net.Socket

这是一个关于如何使用 net.Servernet.Socket 运行“全功能” (终端) REPL 的示例

【This is an example on how to run a "full-featured" (terminal) REPL using net.Server and net.Socket

以下脚本在端口 1337 启动一个 HTTP 服务器,允许客户端与其 REPL 实例建立套接字连接。

【The following script starts an HTTP server on port 1337 that allows clients to establish socket connections to its REPL instance.】

// repl-server.js
import repl from 'node:repl';
import net from 'node:net';

net
  .createServer((socket) => {
    const r = repl.start({
      prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
      input: socket,
      output: socket,
      terminal: true,
      useGlobal: false,
    });
    r.on('exit', () => {
      socket.end();
    });
    r.context.socket = socket;
  })
  .listen(1337);// repl-server.js
const repl = require('node:repl');
const net = require('node:net');

net
  .createServer((socket) => {
    const r = repl.start({
      prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
      input: socket,
      output: socket,
      terminal: true,
      useGlobal: false,
    });
    r.on('exit', () => {
      socket.end();
    });
    r.context.socket = socket;
  })
  .listen(1337);

下面的内容实现了一个客户端,可以通过端口 1337 与上述定义的服务器建立套接字连接。

【While the following implements a client that can create a socket connection with the above defined server over port 1337.】

// repl-client.js
import net from 'node:net';
import process from 'node:process';

const sock = net.connect(1337);

process.stdin.pipe(sock);
sock.pipe(process.stdout);

sock.on('connect', () => {
  process.stdin.resume();
  process.stdin.setRawMode(true);
});

sock.on('close', () => {
  process.stdin.setRawMode(false);
  process.stdin.pause();
  sock.removeListener('close', done);
});

process.stdin.on('end', () => {
  sock.destroy();
  console.log();
});

process.stdin.on('data', (b) => {
  if (b.length === 1 && b[0] === 4) {
    process.stdin.emit('end');
  }
});// repl-client.js
const net = require('node:net');

const sock = net.connect(1337);

process.stdin.pipe(sock);
sock.pipe(process.stdout);

sock.on('connect', () => {
  process.stdin.resume();
  process.stdin.setRawMode(true);
});

sock.on('close', () => {
  process.stdin.setRawMode(false);
  process.stdin.pause();
  sock.removeListener('close', done);
});

process.stdin.on('end', () => {
  sock.destroy();
  console.log();
});

process.stdin.on('data', (b) => {
  if (b.length === 1 && b[0] === 4) {
    process.stdin.emit('end');
  }
});

要运行示例,请在你的计算机上打开两个不同的终端,在一个终端中使用 node repl-server.js 启动服务器,另一个终端中使用 node repl-client.js

【To run the example open two different terminals on your machine, start the server with node repl-server.js in one terminal and node repl-client.js on the other.】

来自 https://gist.github.com/TooTallNate/2209310的原始代码。

通过 curl 使用 REPL#>

【REPL over curl

这是一个关于如何在 curl() 上运行 REPL 实例的示例

【This is an example on how to run a REPL instance over curl()

以下脚本在端口 8000 上启动一个 HTTP 服务器,能够接受通过 curl() 建立的连接。

【The following script starts an HTTP server on port 8000 that can accept a connection established via curl().】

import http from 'node:http';
import repl from 'node:repl';

const server = http.createServer((req, res) => {
  res.setHeader('content-type', 'multipart/octet-stream');

  repl.start({
    prompt: 'curl repl> ',
    input: req,
    output: res,
    terminal: false,
    useColors: true,
    useGlobal: false,
  });
});

server.listen(8000);const http = require('node:http');
const repl = require('node:repl');

const server = http.createServer((req, res) => {
  res.setHeader('content-type', 'multipart/octet-stream');

  repl.start({
    prompt: 'curl repl> ',
    input: req,
    output: res,
    terminal: false,
    useColors: true,
    useGlobal: false,
  });
});

server.listen(8000);

当上述脚本正在运行时,你可以使用 curl() 连接到服务器,并通过运行 curl --no-progress-meter -sSNT. localhost:8000 连接到它的 REPL 实例。

【When the above script is running you can then use curl() to connect to the server and connect to its REPL instance by running curl --no-progress-meter -sSNT. localhost:8000.】

警告 这个示例仅用于教育目的,演示如何使用不同的 I/O 流启动 Node.js REPL。
在生产环境或任何涉及安全性的场景中,不应 使用此示例,除非采取了额外的防护措施。
如果需要在实际应用中实现 REPL,请考虑采用能够降低这些风险的替代方法,例如使用安全的输入机制并避免开放的网络接口。

来自 https://gist.github.com/TooTallNate/2053342的原始代码。

Node.js 中文网 - 粤ICP备13048890号