添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • readline.clearLine(stream, dir[, callback])
  • readline.clearScreenDown(stream[, callback])
  • readline.createInterface(options)
  • completer 函数的使用
  • readline.cursorTo(stream, x[, y][, callback])
  • readline.moveCursor(stream, dx, dy[, callback])
  • readline.emitKeypressEvents(stream[, interface])
  • 示例:微型 CLI
  • 示例:逐行读取文件流
  • TTY 键绑定
  • readline.clearLine(stream, dir[, callback])
  • readline.clearScreenDown(stream[, callback])
  • readline.createInterface(options)
  • completer 函数的使用
  • readline.cursorTo(stream, x[, y][, callback])
  • readline.moveCursor(stream, dx, dy[, callback])
  • readline.emitKeypressEvents(stream[, interface])
  • 示例:微型 CLI
  • 示例:逐行读取文件流
  • TTY 键绑定
  • 源代码: lib/readline.js

    node:readline 模块提供了一个接口,用于一次一行地从 可读 流(例如 process.stdin )中读取数据。

    要使用基于 promise 的 API:

    import * as readline from 'node:readline/promises';const readline = require('node:readline/promises');

    要使用回调和同步的 API:

    import * as readline from 'node:readline';const readline = require('node:readline');

    下面的简单示例阐明了 node:readline 模块的基本用法。

    import * as readline from 'node:readline/promises';
    import { stdin as input, stdout as output } from 'node:process';
    const rl = readline.createInterface({ input, output });
    const answer = await rl.question('What do you think of Node.js? ');
    console.log(`Thank you for your valuable feedback: ${answer}`);
    rl.close();const readline = require('node:readline');
    const { stdin: input, stdout: output } = require('node:process');
    const rl = readline.createInterface({ input, output });
    rl.question('What do you think of Node.js? ', (answer) => {
      // TODO: Log the answer in a database
      console.log(`Thank you for your valuable feedback: ${answer}`);
      rl.close();
    });

    一旦调用此代码,则 Node.js 应用将不会终止,直到 readline.Interface 关闭,因为接口在 input 流上等待接收数据。

    类: InterfaceConstructor #

  • <EventEmitter>
  • InterfaceConstructor 类的实例是使用 readlinePromises.createInterface() 或 readline.createInterface() 方法构造的。 每个实例都与单个 input 可读 流和单个 output 可写 流相关联。 output 流用于打印到达并从 input 流中读取的用户输入的提示。

    事件: 'close' #

    #

    #

    #

  • 'SIGTSTP' 和 'SIGCONT' 。)
  • 调用监听器函数时不传入任何参数。

    rl.on('pause', () => {
      console.log('Readline paused.');
    }); 

    事件: 'resume' #

    #

    fg(1p) 将(即 SIGTSTP )带回前台。

    如果 input 流在 SIGTSTP 请求之前暂停,则不会触发此事件。

    调用监听器函数时不传入任何参数。

    rl.on('SIGCONT', () => {
      // `prompt` will automatically resume the stream
      rl.prompt();
    }); 

    Windows 不支持 'SIGCONT' 事件。

    事件: 'SIGINT' #

    #

    fg(1p) 恢复程序时,则将触发 'pause' 和 'SIGCONT' 事件。 这些可用于恢复 input 流。

    如果 input 在进程发送到后台之前暂停,则不会触发 'pause' 和 'SIGCONT' 事件。

    调用监听器函数时不传入任何参数。

    rl.on('SIGTSTP', () => {
      // This will override SIGTSTP and prevent the program from going to the
      // background.
      console.log('Caught SIGTSTP.');
    }); 

    Windows 不支持 'SIGTSTP' 事件。

    rl.close() #

    #

    #

  • <boolean> 如果为 true ,则防止光标位置重置为 0 。
  • rl.prompt() 方法将配置为 prompt 的 InterfaceConstructor 实例写入 output 中的新行,以便为用户提供用于提供输入的新位置。

    当调用时,如果 rl.prompt() 流已暂停,则 rl.prompt() 将恢复 input 流。

    如果 InterfaceConstructor 是在 output 设置为 null 或 undefined 的情况下创建的,则不会写入提示。

    rl.resume() #

    #

  • <string>
  • rl.setPrompt() 方法设置了在调用 rl.prompt() 时将写入 output 的提示。

    rl.getPrompt() #

  • <string> 当前的提示字符串
  • rl.getPrompt() 方法返回 rl.prompt() 使用的当前提示。

    rl.write(data[, key]) #

  • <string>
  • key <Object>
  • ctrl <boolean> true 表示 控制键 钥匙。
  • meta <boolean> true 表示 元 钥匙。
  • shift <boolean> true 表示 转移 钥匙。
  • name <string> 键的名称。
  • rl.write() 方法会将 data 或由 key 标识的键序列写入 output 。 仅当 output 是 TTY 文本终端时才支持 key 参数。 有关组合键列表,请参阅 TTY 键绑定 。

    如果指定了 key ,则忽略 data 。

    当调用时,如果 rl.write() 流已暂停,则 rl.write() 将恢复 input 流。

    如果 InterfaceConstructor 是在 output 设置为 null 或 undefined 的情况下创建的,则不会写入 data 和 key 。

    rl.write('Delete this!');
    // Simulate Ctrl+U to delete the line written previously
    rl.write(null, { ctrl: true, name: 'u' }); 

    rl.write() 方法会将数据写入 readline Interface 的 input ,就好像它是由用户提供的一样。

    rl[Symbol.asyncIterator]() #

  • <AsyncIterator>
  • 创建 AsyncIterator 对象,该对象遍历输入流中的每一行作为字符串。 此方法允许通过 for await...of 循环异步迭代 InterfaceConstructor 对象。

    输入流中的错误不会被转发。

    如果循环以 break 、 throw 或 return 终止,则将调用 rl.close() 。 换句话说,迭代 InterfaceConstructor 将始终完全消费输入流。

    性能无法与传统的 'line' 事件 API 相提并论。 对于性能敏感的应用,请改用 'line' 。

    async function processLineByLine() {
      const rl = readline.createInterface({
        // ...
      for await (const line of rl) {
        // Each line in the readline input will be successively available here as
        // `line`.
    } 

    readline.createInterface() 将在调用后开始使用输入流。 在接口创建和异步迭代之间进行异步操作可能会导致丢失行。

    rl.line #

    'line' 事件。

    一个可能的用例如下:

    const values = ['lorem ipsum', 'dolor sit amet'];
    const rl = readline.createInterface(process.stdin);
    const showResults = debounce(() => {
      console.log(
        '\n',
        values.filter((val) => val.startsWith(rl.line)).join(' '),
    }, 300);
    process.stdin.on('keypress', (c, k) => {
      showResults();
    }); 

    rl.cursor #

  • <number> | <undefined>
  • 相对于 rl.line 的光标位置。

    当从 TTY 流读取输入时,这将跟踪当前光标在输入字符串中的位置。 光标的位置决定了在处理输入时将被修改的输入字符串部分,以及将渲染终端插入符号的列。

    rl.getCursorPos() #

  • <Object>
  • rows <number> 光标当前所在的提示行
  • cols <number> 光标当前所在的屏幕列
  • 返回光标相对于输入提示 + 字符串的实际位置。 长输入(换行)字符串以及多行提示都包含在计算中。

    Promises API #

    类: readlinePromises.Interface #

  • <readline.InterfaceConstructor>
  • readlinePromises.Interface 类的实例是使用 readlinePromises.createInterface() 方法构造的。 每个实例都与单个 input 可读 流和单个 output 可写 流相关联。 output 流用于打印到达并从 input 流中读取的用户输入的提示。

    rl.question(query[, options]) #
  • <string> 要写入 output 的语句或查询,位于提示之前。
  • options <Object>
  • signal <AbortSignal> 可选择允许使用 AbortSignal 取消 question() 。
  • 返回: <Promise> 使用用户响应 query 的输入履行的 promise。
  • rl.question() 方法通过将 query 写入 output 来显示 query ,等待在 input 上提供用户输入,然后调用 callback 函数,将提供的输入作为第一个参数传入。

    当调用时,如果 rl.question() 流已暂停,则 rl.question() 将恢复 input 流。

    如果 readlinePromises.Interface 是在 output 设置为 null 或 undefined 的情况下创建的,则不会写入 query 。

    如果问题在 rl.close() 之后被调用,则它返回被拒绝的 promise。

    用法示例:

    const answer = await rl.question('What is your favorite food? ');
    console.log(`Oh, so your favorite food is ${answer}`); 

    使用 AbortSignal 取消问题。

    const signal = AbortSignal.timeout(10_000);
    signal.addEventListener('abort', () => {
      console.log('The food question timed out');
    }, { once: true });
    const answer = await rl.question('What is your favorite food? ', { signal });
    console.log(`Oh, so your favorite food is ${answer}`); 

    类: readlinePromises.Readline #

    #
  • <stream.Writable> TTY 流。
  • options <Object>
  • autoCommit <boolean> 如果是 true ,则不需要调用 rl.commit() 。
  • rl.clearLine() 方法在待处理动作的内部列表中添加一个动作,该动作在 dir 标识的指定方向上清除关联 stream 的当前行。 调用 rl.commit() 看看这个方法的效果,除非 autoCommit: true 传给了构造函数。

    rl.clearScreenDown() #
    #
  • <Promise>
  • rl.commit() 方法将所有待处理的操作发送到关联的 stream 并清除待处理操作的内部列表。

    rl.cursorTo(x[, y]) #
  • <integer>
  • y <integer>
  • 返回: 自身
  • rl.cursorTo() 方法向待处理动作的内部列表添加一个动作,该动作将光标移动到相关 stream 中指定的位置。 调用 rl.commit() 看看这个方法的效果,除非 autoCommit: true 传给了构造函数。

    rl.moveCursor(dx, dy) #
  • <integer>
  • dy <integer>
  • 返回: 自身
  • rl.moveCursor() 方法向待处理操作的内部列表添加一个操作,该操作将光标相对于关联的 stream 中的当前位置移动。 调用 rl.commit() 看看这个方法的效果,除非 autoCommit: true 传给了构造函数。

    rl.rollback() #

    #

  • <Object>
  • input <stream.Readable> 要收听的 可读 流。 此选项是必需的。
  • output <stream.Writable> 要写入 readline 数据的 可写 流。
  • completer <Function> 可选的用于制表符自动补全的函数。
  • terminal <boolean> 如果 input 和 output 流应该被视为终端,并且写入了 ANSI/VT100 转义码,则为 true 。 默认值: 在实例化时检查 output 流上的 isTTY 。
  • history <string[]> 历史行的初始列表。 仅当 terminal 由用户或内部的 output 检查设置为 true 时,此选项才有意义,否则历史缓存机制根本不会初始化。 默认值: [] 。
  • historySize <number> 保留的最大历史行数。 要禁用历史记录,则将此值设置为 0 。 仅当 terminal 由用户或内部的 output 检查设置为 true 时,此选项才有意义,否则历史缓存机制根本不会初始化。 默认值: 30 。
  • removeHistoryDuplicates <boolean> 如果为 true ,则当添加到历史列表的新输入行与旧输入行重复时,这将从列表中删除旧行。 默认值: false 。
  • prompt <string> 要使用的提示字符串。 默认值: '> ' 。
  • crlfDelay <number> 如果 \r 和 \n 之间的延迟超过 crlfDelay 毫秒,则 \r 和 \n 都将被视为单独的行尾输入。 crlfDelay 将被强制为不小于 100 的数字。 它可以设置为 Infinity ,在这种情况下, \r 后跟 \n 将始终被视为单个换行符(这对于带有 \r\n 行分隔符的 读取文件 可能是合理的)。 默认值: 100 。
  • escapeCodeTimeout <number> readlinePromises 将等待字符的时长(当以毫秒为单位读取不明确的键序列时,既可以使用目前读取的输入形成完整的键序列,又可以采用额外的输入来完成更长的键序列)。 默认值: 500 。
  • tabSize <integer> 一个制表符等于的空格数(最小为 1)。 默认值: 8 。
  • 返回: <readlinePromises.Interface>
  • readlinePromises.createInterface() 方法创建新的 readlinePromises.Interface 实例。

    const readlinePromises = require('node:readline/promises');
    const rl = readlinePromises.createInterface({
      input: process.stdin,
      output: process.stdout,
    }); 

    一旦创建了 readlinePromises.Interface 实例,则最常见的场景就是监听 'line' 事件:

    rl.on('line', (line) => {
      console.log(`Received: ${line}`);
    }); 

    如果此实例的 terminal 是 true ,则如果它定义了 output.columns 属性,并且如果或当列发生变化时( process.stdout 会当其是终端时自动执行此操作)在 output 上触发 'resize' 事件,则 output 流将获得最佳的兼容性。

    completer 函数的使用 #

    <Promise> ,或者是异步的:

    async function completer(linePartial) {
      await someAsyncWork();
      return [['123'], linePartial];
    } 

    回调接口 #

    #

  • <readline.InterfaceConstructor>
  • readline.Interface 类的实例是使用 readline.createInterface() 方法构造的。 每个实例都与单个 input 可读 流和单个 output 可写 流相关联。 output 流用于打印到达并从 input 流中读取的用户输入的提示。

    rl.question(query[, options], callback) #
  • <string> 要写入 output 的语句或查询,位于提示之前。
  • options <Object>
  • signal <AbortSignal> 可选择允许使用 AbortController 取消 question() 。
  • callback <Function> 使用用户输入调用的回调函数以响应 query 。
  • rl.question() 方法通过将 query 写入 output 来显示 query ,等待在 input 上提供用户输入,然后调用 callback 函数,将提供的输入作为第一个参数传入。

    当调用时,如果 rl.question() 流已暂停,则 rl.question() 将恢复 input 流。

    如果 readline.Interface 是在 output 设置为 null 或 undefined 的情况下创建的,则不会写入 query 。

    传给 rl.question() 的 callback 函数不遵循接受 Error 对象或 null 作为第一个参数的典型模式。 以提供的答案作为唯一参数调用 callback 。

    在 rl.close() 之后调用 rl.question() 会报错。

    用法示例:

    rl.question('What is your favorite food? ', (answer) => {
      console.log(`Oh, so your favorite food is ${answer}`);
    }); 

    使用 AbortController 取消问题。

    const ac = new AbortController();
    const signal = ac.signal;
    rl.question('What is your favorite food? ', { signal }, (answer) => {
      console.log(`Oh, so your favorite food is ${answer}`);
    signal.addEventListener('abort', () => {
      console.log('The food question timed out');
    }, { once: true });
    setTimeout(() => ac.abort(), 10000); 

    readline.clearLine(stream, dir[, callback]) #

  • <Function> 操作完成后调用。
  • 返回: <boolean> false 如果 stream 希望调用代码在继续写入额外数据之前等待 'drain' 事件触发; 否则 true 。
  • readline.clearLine() 方法在 dir 标识的指定方向上清除给定 TTY 流的当前行。

    readline.clearScreenDown(stream[, callback]) #

  • <stream.Writable>
  • callback <Function> 操作完成后调用。
  • 返回: <boolean> false 如果 stream 希望调用代码在继续写入额外数据之前等待 'drain' 事件触发; 否则 true 。
  • readline.clearScreenDown() 方法从光标的当前位置向下清除给定的 TTY 流。

    readline.createInterface(options) #

  • <stream.Readable> 要收听的 可读 流。 此选项是必需的。
  • output <stream.Writable> 要写入 readline 数据的 可写 流。
  • completer <Function> 可选的用于制表符自动补全的函数。
  • terminal <boolean> 如果 input 和 output 流应该被视为终端,并且写入了 ANSI/VT100 转义码,则为 true 。 默认值: 在实例化时检查 output 流上的 isTTY 。
  • history <string[]> 历史行的初始列表。 仅当 terminal 由用户或内部的 output 检查设置为 true 时,此选项才有意义,否则历史缓存机制根本不会初始化。 默认值: [] 。
  • historySize <number> 保留的最大历史行数。 要禁用历史记录,则将此值设置为 0 。 仅当 terminal 由用户或内部的 output 检查设置为 true 时,此选项才有意义,否则历史缓存机制根本不会初始化。 默认值: 30 。
  • removeHistoryDuplicates <boolean> 如果为 true ,则当添加到历史列表的新输入行与旧输入行重复时,这将从列表中删除旧行。 默认值: false 。
  • prompt <string> 要使用的提示字符串。 默认值: '> ' 。
  • crlfDelay <number> 如果 \r 和 \n 之间的延迟超过 crlfDelay 毫秒,则 \r 和 \n 都将被视为单独的行尾输入。 crlfDelay 将被强制为不小于 100 的数字。 它可以设置为 Infinity ,在这种情况下, \r 后跟 \n 将始终被视为单个换行符(这对于带有 \r\n 行分隔符的 读取文件 可能是合理的)。 默认值: 100 。
  • escapeCodeTimeout <number> readline 将等待字符的时长(当以毫秒为单位读取不明确的键序列时,既可以使用目前读取的输入形成完整的键序列,又可以采用额外的输入来完成更长的键序列)。 默认值: 500 。
  • tabSize <integer> 一个制表符等于的空格数(最小为 1)。 默认值: 8 。
  • signal <AbortSignal> 允许使用中止信号关闭接口。 中止信号将在内部调用接口上的 close 。
  • 返回: <readline.Interface>
  • readline.createInterface() 方法创建新的 readline.Interface 实例。

    const readline = require('node:readline');
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    }); 

    一旦创建了 readline.Interface 实例,则最常见的场景就是监听 'line' 事件:

    rl.on('line', (line) => {
      console.log(`Received: ${line}`);
    }); 

    如果此实例的 terminal 是 true ,则如果它定义了 output.columns 属性,并且如果或当列发生变化时( process.stdout 会当其是终端时自动执行此操作)在 output 上触发 'resize' 事件,则 output 流将获得最佳的兼容性。

    当使用 stdin 作为输入创建 readline.Interface 时,程序将不会终止,直到它收到 EOF 字符 。 要在不等待用户输入的情况下退出,则调用 process.stdin.unref() 。

    completer 函数的使用 #

    #

  • <number>
  • callback <Function> 操作完成后调用。
  • 返回: <boolean> false 如果 stream 希望调用代码在继续写入额外数据之前等待 'drain' 事件触发; 否则 true 。
  • readline.cursorTo() 方法将光标移动到给定的 TTY stream 中的指定位置。

    readline.moveCursor(stream, dx, dy[, callback]) #

  • <number>
  • callback <Function> 操作完成后调用。
  • 返回: <boolean> false 如果 stream 希望调用代码在继续写入额外数据之前等待 'drain' 事件触发; 否则 true 。
  • readline.moveCursor() 方法将光标相对于其在给定 TTY stream 中的当前位置移动。

    readline.emitKeypressEvents(stream[, interface]) #

  • <stream.Readable>
  • interface <readline.InterfaceConstructor>
  • readline.emitKeypressEvents() 方法使给定的 可读 流开始触发与接收到的输入相对应的 'keypress' 事件。

    可选地, interface 指定 readline.Interface 实例,当检测到复制粘贴输入时禁用自动补齐。

    如果 stream 是 TTY ,则它必须处于原始模式。

    如果 input 是终端,则它会被其 input 上的任何逐行读取实例自动调用。 关闭 readline 实例不会阻止 input 触发 'keypress' 事件。

    readline.emitKeypressEvents(process.stdin);
    if (process.stdin.isTTY)
      process.stdin.setRawMode(true); 

    示例:微型 CLI #

    #

    fs.ReadStream API 和 for await...of 循环:

    const fs = require('node:fs');
    const readline = require('node:readline');
    async function processLineByLine() {
      const fileStream = fs.createReadStream('input.txt');
      const rl = readline.createInterface({
        input: fileStream,
        crlfDelay: Infinity,
      // Note: we use the crlfDelay option to recognize all instances of CR LF
      // ('\r\n') in input.txt as a single line break.
      for await (const line of rl) {
        // Each line in input.txt will be successively available here as `line`.
        console.log(`Line from file: ${line}`);
    processLineByLine(); 

    或者,可以使用 'line' 事件:

    const fs = require('node:fs');
    const readline = require('node:readline');
    const rl = readline.createInterface({
      input: fs.createReadStream('sample.txt'),
      crlfDelay: Infinity,
    rl.on('line', (line) => {
      console.log(`Line from file: ${line}`);
    }); 

    目前, for await...of 循环可能会慢一点。 如果 async / await 流量和速度都必不可少,则可以应用混合方法:

    const { once } = require('node:events');
    const { createReadStream } = require('node:fs');
    const { createInterface } = require('node:readline');
    (async function processLineByLine() {
      try {
        const rl = createInterface({
          input: createReadStream('big-file.txt'),
          crlfDelay: Infinity,
        rl.on('line', (line) => {
          // Process the line.
        await once(rl, 'close');
        console.log('File processed.');
      } catch (err) {
        console.error(err);
    })(); 

    TTY 键绑定 #