NodeJS 有办法擦除输出的最后一行吗?

aor9mmx1  于 2023-03-17  发布在  Node.js
关注(0)|答案(6)|浏览(175)

一个非常简单的程序,打印3行输出:

console.log('a');
console.log('b');
console.log('c');

程序是否有办法在最后一行打印后删除它?

console.log('a');
console.log('b');
console.log('c');
clearLastLine();
console.log('C');

这将产生:

a
b
C
2j4z5cfb

2j4z5cfb1#

简单的解决方案是不打印换行符(即不使用console.log)。

  • 使用process.stdout.write打印不带EOL字符的行。
  • 使用回车(\r)字符返回到行开始。
  • 使用\e[K清除从光标位置到行尾的所有字符。

示例:

process.stdout.write("000");
process.stdout.write("\n111");
process.stdout.write("\n222");

对于此行,输出将为:

000
111
222

但是,如果执行:

process.stdout.write("000");
process.stdout.write("\n111");
process.stdout.write("\n222");
process.stdout.write("\r\x1b[K")
process.stdout.write("333");

输出为:

000
111
222\r\x1b[K
333

但是,终端将显示:

000
111
333
t3irkdon

t3irkdon2#

方式一:

const clearLastLine = () => {
  process.stdout.moveCursor(0, -1) // up one line
  process.stdout.clearLine(1) // from cursor to end
}

方式二:

const readline = require('readline')

const clearLastLine = () => {
  readline.moveCursor(process.stdout, 0, -1) // up one line
  readline.clearLine(process.stdout, 1) // from cursor to end
}

方式三:

const ESC = '\x1b' // ASCII escape character
const CSI = ESC + '[' // control sequence introducer

const clearLastLine = () => {
  process.stdout.write(CSI + 'A') // moves cursor up one line
  process.stdout.write(CSI + 'K') // clears from cursor to line end
}

方式1使用内置tty模块提供的方法。
方式2使用内置的readline模块。
方式3使用ANSI escape sequences
我通过查看log-update的源代码了解了ANSI escape sequences,这是我从dthreeanswer中找到的,在做了更多的研究之后,我了解了内置的readlinetty模块。
通过阅读Node.js的源代码,我了解到方式1中使用的方法本质上是方式2中使用的方法的 Package 器,方式2中使用的方法本质上是方式3中使用的方法的 Package 器。因此,每种方式最终在幕后做的事情基本相同。我将方式从高级别到低级别进行了排序。
我建议使用方式1而不是方式2,使用方式2而不是方式3,主要是因为我认为方式1的代码更少,而且更清晰(因此更可读),且路2代码更少且更清晰(因此可读性更强),并且性能改进(如果有的话)通过使用较低级别的方式实现的可能是可以忽略的。但是,我认为方式3避免了加载内置的readline模块。
这个解决方案(无论如何)假设你的光标在你的程序调用clearLastLine()之前是在一个空行的开始。正如Gajushis answer中所述,如果你的光标在最后一行的结尾,解决方案会更简单。那么你能使用process.stdout.write()(而不是console.log())打印最后一行而不带尾随换行符吗?
或者,如果你不需要打印最后一行,解决方案甚至更简单。所有这些对stdout的修改都是code smell吗?你能重新设计你的代码,让最后一行根本不打印吗?
在我的例子中,我正在测试我编写的一个调用console.error()的帮助函数,我不希望记录的错误消息显示在我的测试输出中,所以我没有让我的帮助函数调用console.error(),我可以让它抛出错误(或仅返回错误代码和/或消息或布尔值)。然后,如果helper函数抛出错误,调用helper函数的主程序可以调用console.error()(或者返回一个错误代码和/或消息或者false)或者我可以传递一个布尔值flag argument给我的helper函数,告诉它是否记录一个错误,或者我可以重定向stderr,或者是全局的console或者是stubconsole.error()等等。
如果要清除写入system.stdout的最后三行,可以执行以下操作:

const clearLastLines = (count) => {
  process.stdout.moveCursor(0, -count)
  process.stdout.clearScreenDown()
}

clearLastLines(3)
mznpcxlj

mznpcxlj3#

以下是我的工作:

process.stdout.clearLine();
process.stdout.cursorTo(0);
yyyllmsg

yyyllmsg4#

您可以使用logUpdate NPM模块或vorpal NPM模块,这两个模块都可以完成此任务。

km0tfn4u

km0tfn4u5#

唯一一个对我有用的模块是single-line-log,它没有删除进度条之前的所有内容
安装时:

npm i single-line-log

导入时使用:

var log = require('single-line-log').stdout;

然后,不要使用console.log()记录进度条,只需使用log()

// OLD:
while (task_is_running) {
    console.log(Progress.update())
}

// NEW:
while (task_is_running) {
    log(Progress.update())
}

结合clui的进度条,这工作得很好。

6ss1mwsb

6ss1mwsb6#

有一个简单的解决方案:

process.stdout.write(`\x1Bc\rData left: ${currentPercentage}%`)

这将打印如下内容:“剩余数据:100%"...并且通过使用它,你会在每次迭代后清除屏幕。
“\x1Bc”清除该行,"\r“返回到第0列。

相关问题