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(); })();
问题原因
- 行数计算逻辑错误:原
clearLines函数通过新旧文本行数差值计算需要清除的行数,而每次输出的文本都是两行(含\n),导致差值为0,仅清除1行,留下旧内容残留。 - 清除范围不足:使用
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
相关产品推荐
相关产品推荐

