-
-
Save vsemozhetbyt/3b225c62f226e8d71156c6029ce298eb to your computer and use it in GitHub Desktop.
| /******************************************************************************/ | |
| 'use strict'; | |
| /******************************************************************************/ | |
| // progress bar as a module | |
| module.exports = function pb(edge = 0) { | |
| const rl = require('readline'); | |
| const DEFAULT_FREQ = 500; | |
| const HUNDRED_PERCENT = 100; | |
| const PB_LENGTH = 50; | |
| const PB_SCALE = HUNDRED_PERCENT / PB_LENGTH; | |
| const NANOSECONDS_PER_SECOND = 1e9; | |
| const hrStart = process.hrtime(); | |
| function clearLine() { | |
| rl.cursorTo(process.stdout, 0); | |
| rl.clearLine(process.stdout, 0); | |
| } | |
| function getTimePast() { | |
| const hrEnd = process.hrtime(hrStart); | |
| return `${ | |
| ((hrEnd[0] * NANOSECONDS_PER_SECOND + hrEnd[1]) / NANOSECONDS_PER_SECOND).toFixed(1) | |
| } s`; | |
| } | |
| return { | |
| edge, | |
| stat: 0, | |
| start(freq = DEFAULT_FREQ) { | |
| this.updater = setInterval(() => { this.update(); }, freq); | |
| }, | |
| update(stat = this.stat) { | |
| const statPercent = | |
| stat === this.edge || stat > this.edge ? | |
| HUNDRED_PERCENT : | |
| stat / this.edge * HUNDRED_PERCENT; | |
| const barsNumber = Math.floor(statPercent / PB_SCALE); | |
| const padsNumber = PB_LENGTH - barsNumber; | |
| clearLine(); | |
| process.stdout.write( | |
| `${'█'.repeat(barsNumber)}${'░'.repeat(padsNumber)} ${statPercent.toFixed(1)}% ${getTimePast()} (${stat.toLocaleString()} of ${this.edge.toLocaleString()})` | |
| ); | |
| }, | |
| end() { | |
| clearInterval(this.updater); | |
| this.stat = this.edge; | |
| this.update(); | |
| console.log('\n'); | |
| }, | |
| clear() { | |
| clearInterval(this.updater); | |
| clearLine(); | |
| }, | |
| }; | |
| }; | |
| /******************************************************************************/ |
1. Подключение модуля (при встраивании функции в код этот шаг не нужен):
const pb = require('./pb.js');
2. Пример использование в асинхронных операциях:
const pbAsync = pb(fs.statSync(filePath).size); // число, которое будет означать 100% выполнения
pbAsync.start(1000); //частота обновления, по умолчанию 500 ms
readlineInterface.on('line', line => {
pbAsync.stat += Buffer.byteLength(line, encoding) + 1; //дать знать о степени продвижения
//...
}).on('close', () => {
pbAsync.end();
});3. Пример использования в синхронных операциях.
const pbSync = pb(array.length); // число, которое будет означать 100% выполнения
array.forEach((elem, i) => {
if (i % 1000 === 0) pbSync.update(i); //обновлять после каждой тысячи элементов, передавая степень продвижения
//...
});
pbSync.end();4. Интерфейс.
const pb1 = pb(edge); — инициализация.
pb1.start(freq) — запуск обновления по таймеру (для асинхронных операций; следует предусмотреть передачу продвижения при помощи периодического присваивания текущего состояния переменной pb1.stat).
pb1.update(stat) — принудительное обновление (для синхронных операций; следует ограничивать частоту запуска).
pb1.end() — остановка таймера (если он был запущен) и завершающее обновление индикатора (для обоих случаев) с переходом на новую строку.
pb1.clear() — остановить таймер (если он был запущен) и стереть индикатор. Полезно, например, при досрочном прерывании отслеживаемого процесса из-за ошибки.
Во время обновления текущего индикатора следует старательно воздерживаться от вывода данных в консоль. Если нужен вывод в консоль, лучше использовать индикатор в заголовке окна.

Uh oh!
There was an error while loading. Please reload this page.