Skip to content

Instantly share code, notes, and snippets.

@vsemozhetbyt
Last active January 20, 2017 18:20
Show Gist options
  • Select an option

  • Save vsemozhetbyt/3b225c62f226e8d71156c6029ce298eb to your computer and use it in GitHub Desktop.

Select an option

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();
},
};
};
/******************************************************************************/
@vsemozhetbyt
Copy link
Copy Markdown
Author

vsemozhetbyt commented Apr 19, 2016

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() — остановить таймер (если он был запущен) и стереть индикатор. Полезно, например, при досрочном прерывании отслеживаемого процесса из-за ошибки.

Во время обновления текущего индикатора следует старательно воздерживаться от вывода данных в консоль. Если нужен вывод в консоль, лучше использовать индикатор в заголовке окна.

@vsemozhetbyt
Copy link
Copy Markdown
Author

pb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment