Як виміряти продуктивність JS-коду?
Швидкі виміри (інструментування в коді)
Браузер
javascript
// Точний таймер (у мс, з частками)
const t0 = performance.now();
// ... код ...
const t1 = performance.now();
console.log(`Час: ${(t1 - t0).toFixed(2)} ms`);javascript
// User Timing API: мітки і вимірювання
performance.mark('A');
// ... код ...
performance.mark('B');
performance.measure('my-op', 'A', 'B');
console.table(performance.getEntriesByName('my-op'));javascript
// Швидко і просто
console.time('op');
// ... код ...
console.timeEnd('op');Node.js
javascript
// perf_hooks - монотонні таймери
const { performance, PerformanceObserver } = require('node:perf_hooks');
performance.mark('A');
// ... код ...
performance.mark('B');
performance.measure('op', 'A', 'B');
new PerformanceObserver(list => console.table(list.getEntries()))
.observe({ entryTypes: ['measure'] });Профілювання (щоб зрозуміти, "де" гальмує)
Браузер DevTools
- Performance (або Performance Insights): запис → отримаєш flame chart (гарячі функції), FPS, layout/recalc style, long tasks (≥50 ms).
- Memory: Heap snapshot / Allocation instrumentation - шукаємо витоки і "сміття".
- Coverage: скільки JS/CSS реально виконується (впливає на TBT).
Node.js
node --inspectі Chrome DevTools → CPU profile, heap.node --prof+prof-processабо clinic.js / 0x для зручних графів полум'я.
Мікробенчмарки (порівняти реалізації)
- Benchmark.js / tinybench - роблять прогрів JIT, багато ітерацій, статистику.
javascript
import Benchmark from 'benchmark';
const suite = new Benchmark.Suite();
function a(arr){ /* варіант A */ }
function b(arr){ /* варіант B */ }
suite
.add('A', () => a(data))
.add('B', () => b(data))
.on('cycle', e => console.log(String(e.target)))
.on('complete', function () {
console.log('Faster:', this.filter('fastest').map('name'));
})
.run({ async: true });Важливо: прогрівай тест (discard first run), фіксуй вхідні дані, запускай кілька прогонів, вимикай зайві вкладки/розширення.
Вимірювання "переживаності" UI
- Long Tasks API: ловимо блокування головного потоку.
javascript
new PerformanceObserver((list) => {
for (const e of list.getEntries()) {
console.log('Long task', e.duration.toFixed(1), 'ms');
}
}).observe({ entryTypes: ['longtask'] });- rAF/FPS: простий індикатор плавності.
javascript
let last = performance.now(), frames = 0;
function tick(ts){
frames++;
if (ts - last >= 1000) { console.log('FPS:', frames); frames = 0; last = ts; }
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);Мережеві і рендер-метрики (сторінкові)
- Navigation/Resource Timing (
performance.getEntriesByType('navigation'|'resource')) - TTFB, завантаження ресурсів. - Core Web Vitals (LCP, CLS, INP/TBT) - став web-vitals у реальному трафіку.
- Lighthouse (разово) - регресії, але не замінює польові метрики.
Методика: як міряти коректно
- Сформулюй мету (CPU-частина? GC? Layout? Мережа?).
- Ізолюй контекст: вимкни мережу/DOM, якщо міряєш чистий алгоритм.
- Прогрій JIT: зроби кілька "холостих" запусків.
- Повторення і статистика: медіана/квантилі важливіші за середнє.
- Контролюй шум: фіксуй дані, розмір входу, обмеж фонові процеси.
- Дивись на полум'я (flame chart), а не тільки цифри - оптимізуй "гарячі" вузькі місця.
- Перевіряй регресії в CI (наприклад, невеликий бенч + пороги).
Що міряти в типових сценаріях
- Алгоритм/колекції → microbench (Benchmark.js) +
performance.now. - Інтерактивність UI → DevTools Performance + Long Tasks + FPS.
- Рендер/стилі → вкладки Rendering/Layout/Styles у профайлері, уникай layout-thrashing.
- Пам'ять/витоки → Heap snapshots, Allocation timeline.
- Node API →
perf_hooks, CPU profile, перевірка sync-методів (замінити на async/worker_threads).
Антипатерни
- Один прогін "на око" - шум і JIT спотворять картину.
- Мікробенчі DOM-операцій: результати залежать від реального дерева/стилів. Профілюй у DevTools.
- Порівнювати без однакових вхідних даних.
- Оптимізувати без flamechart - легко "лікувати не те місце".
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.