You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript CLI进度条控制台行清除异常问题求助

CLI进度条控制台行清除异常的解决方案

我在为CLI应用编写进度条功能时,其余功能正常,但控制台行清除存在异常,无法正确展示各执行动作的状态——进度条更新时旧内容残留,无法被完全清除。

相关代码

进度条库代码

import chalk from 'chalk';

export default class ProgressBar {
  total: number;
  current: number = 0;

  barLength = 20;

  progressList: string[] = [];

  previousText = '';

  constructor(total: number, barLength = 20, progressList: string[] = []) {
    this.total = total;
    this.barLength = barLength;
    this.progressList = progressList;
  }

  updateTotal(total: number) {
    this.total = total;
  }

  updateCurrent(current: number) {
    this.current = current;
    this.render();
  }

  render() {
    const active = Math.floor((this.current / this.total) * this.barLength);

    const bar =
      chalk.bgGreenBright(' '.repeat(active)) +
      chalk.bgWhiteBright(' '.repeat(this.barLength - active));
    const progress = `${this.current}/${this.total}`;
    const name = this.progressList[this.current - 1] ?? 'N/A';
    const percentage = Math.floor((this.current / this.total) * 100)
      .toString()
      .padStart(3, '0') + '%';

    const text = `${bar} ${progress} [${percentage}]\nProgress: ${name}`;

    this.clearLines(this.previousText, text);
    this.previousText = text;
    process.stdout.write(text);
  }

  end() {
    const bar = chalk.bgGreenBright(' '.repeat(this.barLength));
    const progress = `${this.total}/${this.total}`;
    const percentage = '100%';

    const text = `${bar} ${progress} [${percentage}]\nProgress: Ended`;
    this.clearLines(this.previousText, text);
    this.previousText = text;

    process.stdout.write(text);
  }

  clearLines = (prevText: string, currText: string) => {
    const prevLines = prevText.split('\n').length;
    const currLines = currText.split('\n').length;
    const linesToClear = Math.max(prevLines - currLines + 1, 0);

    for (let i = 0; i < linesToClear; i++) {
      process.stdout.moveCursor(0, -1);
      process.stdout.clearLine(1);
    }
    process.stdout.cursorTo(0);
  };
}

主程序代码

import fs from 'node:fs';
import path from 'node:path';
import ASS from './classes/ASS';
import ProgressBar from './classes/ProgressBar';

console.log('\n');

const progressBar = new ProgressBar(4, 20, [
    'Importing file',
    'Reading file',
    'Initing ASS Parser Class',
    'Waiting a 5 seconds'
]);

; (async () => {
    progressBar.updateCurrent(0);
    const file = path.join(__dirname, 'files/example.ass');

    progressBar.updateCurrent(1);
    const content = fs.readFileSync(file, 'utf-8');

    progressBar.updateCurrent(2);
    const ass = new ASS(content);

    progressBar.updateCurrent(3);
    await new Promise(res => setTimeout(res, 5000));

    progressBar.end();

})();

问题原因

  1. 行数计算逻辑错误:原clearLines函数通过新旧文本行数差值计算需要清除的行数,而每次输出的文本都是两行(含\n),导致差值为0,仅清除1行,留下旧内容残留。
  2. 清除范围不足:使用clearLine(1)仅清除光标右侧内容,若光标在行首则无法清除整行内容。

解决方案

重写clearLines函数,直接清除之前输出的所有行,并调整清除范围为整行:

修改后的完整进度条库代码

import chalk from 'chalk';

export default class ProgressBar {
  total: number;
  current: number = 0;

  barLength = 20;

  progressList: string[] = [];

  previousText = '';

  constructor(total: number, barLength = 20, progressList: string[] = []) {
    this.total = total;
    this.barLength = barLength;
    this.progressList = progressList;
  }

  updateTotal(total: number) {
    this.total = total;
  }

  updateCurrent(current: number) {
    this.current = current;
    this.render();
  }

  render() {
    const active = Math.floor((this.current / this.total) * this.barLength);

    const bar =
      chalk.bgGreenBright(' '.repeat(active)) +
      chalk.bgWhiteBright(' '.repeat(this.barLength - active));
    const progress = `${this.current}/${this.total}`;
    const name = this.progressList[this.current - 1] ?? 'N/A';
    const percentage = Math.floor((this.current / this.total) * 100)
      .toString()
      .padStart(3, '0') + '%';

    const text = `${bar} ${progress} [${percentage}]\nProgress: ${name}`;

    this.clearLines(this.previousText);
    this.previousText = text;
    process.stdout.write(text);
  }

  end() {
    const bar = chalk.bgGreenBright(' '.repeat(this.barLength));
    const progress = `${this.total}/${this.total}`;
    const percentage = '100%';

    const text = `${bar} ${progress} [${percentage}]\nProgress: Ended`;
    this.clearLines(this.previousText);
    this.previousText = text;
    process.stdout.write(text);
  }

  clearLines = (prevText: string) => {
    const prevLines = prevText.split('\n').length;
    for (let i = 0; i < prevLines; i++) {
      process.stdout.moveCursor(0, -1);
      process.stdout.clearLine(0); // 清除整行内容
    }
    process.stdout.cursorTo(0);
  };
}

修改关键点

  • 移除旧的行数差值计算逻辑,直接根据之前输出文本的行数逐行清除
  • 将clearLine(1)改为clearLine(0),确保清除光标所在行的全部内容
  • 简化clearLines函数的参数,仅传入之前的文本即可完成清除操作

修改后,每次更新进度条时会先完全清除之前输出的内容,再输出新的进度信息,不会出现旧内容残留的问题。

内容的提问来源于stack exchange,提问作者Wraith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:54:53