← Назад к вопросам
Как измерять Performance внутри браузера?
1.0 Junior🔥 221 комментариев
#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Измерение Performance в браузере
Performance — критически важный метрик для веб-приложений. Браузер предоставляет множество встроенных API для измерения различных аспектов производительности: времени загрузки, выполнения кода, рендеринга и взаимодействия пользователя.
Performance API - основные методы
// Основные Web Vitals
const perfData = performance.getEntriesByType('navigation')[0];
console.log('DNS lookup:', perfData.domainLookupEnd - perfData.domainLookupStart);
console.log('TCP connection:', perfData.connectEnd - perfData.connectStart);
console.log('Time to First Byte:', perfData.responseStart - perfData.requestStart);
console.log('DOMContentLoaded:', perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart);
console.log('Load event:', perfData.loadEventEnd - perfData.loadEventStart);
// Всё время загрузки
console.log('Полное время загрузки:', perfData.loadEventEnd - perfData.fetchStart);
Web Vitals - метрики, которые гугл учитывает для SEO
Largest Contentful Paint (LCP) — время отрисовки самого большого контента:
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.renderTime || lastEntry.loadTime);
});
observer.observe({ entryTypes: ['largest-contentful-paint'] });
// Хорошее значение: менее 2.5 секунд
First Input Delay (FID) — задержка первого взаимодействия пользователя:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('FID:', entry.processingDuration);
}
});
observer.observe({ entryTypes: ['first-input'] });
// Хорошее значение: менее 100ms
Cumulative Layout Shift (CLS) — неожиданные сдвиги элементов:
let clsScore = 0;
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsScore += entry.value;
console.log('CLS score:', clsScore);
}
}
});
observer.observe({ entryTypes: ['layout-shift'] });
// Хорошее значение: менее 0.1
Timing API - измерение кастомных операций
// Старт измерения операции
performance.mark('operation-start');
// ... выполняем операцию
for (let i = 0; i < 1000000; i++) {
Math.sqrt(i);
}
// Конец измерения
performance.mark('operation-end');
// Измерить разницу
performance.measure('my-operation', 'operation-start', 'operation-end');
// Получить результат
const measure = performance.getEntriesByName('my-operation')[0];
console.log('Время операции:', measure.duration, 'ms');
Практический пример с интернет-запросом:
async function fetchData(url) {
performance.mark('fetch-start');
try {
const response = await fetch(url);
const data = await response.json();
performance.mark('fetch-end');
performance.measure('fetch-time', 'fetch-start', 'fetch-end');
const measure = performance.getEntriesByName('fetch-time')[0];
console.log(`Fetch занял ${measure.duration.toFixed(2)}ms`);
return data;
} catch (error) {
console.error('Fetch failed:', error);
}
}
Измерение времени выполнения функции
function measurePerformance(fn, label = 'Operation') {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${label}: ${(end - start).toFixed(2)}ms`);
return result;
}
// Использование
measurePerformance(() => {
let sum = 0;
for (let i = 0; i < 10000000; i++) {
sum += i;
}
return sum;
}, 'BigLoop');
// Или для асинхронных функций
async function measureAsync(fn, label = 'Async Operation') {
const start = performance.now();
const result = await fn();
const end = performance.now();
console.log(`${label}: ${(end - start).toFixed(2)}ms`);
return result;
}
PerformanceObserver - мониторинг различных метрик
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Entry:', entry);
}
});
// Слушать несколько типов метрик
observer.observe({
entryTypes: ['navigation', 'paint', 'resource', 'measure']
});
// Очистить
observer.disconnect();
Отслеживание загрузки ресурсов:
const observer = new PerformanceObserver((list) => {
const resources = list.getEntries();
resources.forEach(resource => {
if (resource.duration > 1000) {
console.warn('Медленный ресурс:', {
name: resource.name,
duration: resource.duration,
size: resource.transferSize
});
}
});
});
observer.observe({ entryTypes: ['resource'] });
Memory API - потребление памяти
// Доступно только в Chrome, с флагом --enable-precise-memory-info
if (performance.memory) {
console.log('Используется памяти:', Math.round(performance.memory.usedJSHeapSize / 1048576), 'MB');
console.log('Лимит памяти:', Math.round(performance.memory.jsHeapSizeLimit / 1048576), 'MB');
console.log('Процент использования:',
(performance.memory.usedJSHeapSize / performance.memory.jsHeapSizeLimit * 100).toFixed(1), '%'
);
}
// Мониторинг памяти
setInterval(() => {
if (performance.memory) {
const used = Math.round(performance.memory.usedJSHeapSize / 1048576);
const limit = Math.round(performance.memory.jsHeapSizeLimit / 1048576);
console.log(`Memory: ${used}MB / ${limit}MB`);
}
}, 5000);
Paint Timing - моменты отрисовки
// First Paint - момент первой отрисовки
// First Contentful Paint - момент отрисовки первого контента
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.startTime.toFixed(2)}ms`);
}
});
observer.observe({ entryTypes: ['paint'] });
Navigation Timing - подробная информация о загрузке
function getNavigationTiming() {
const navigation = performance.getEntriesByType('navigation')[0];
return {
'DNS': navigation.domainLookupEnd - navigation.domainLookupStart,
'TCP': navigation.connectEnd - navigation.connectStart,
'TLS': navigation.secureConnectionStart > 0
? navigation.connectEnd - navigation.secureConnectionStart
: 0,
'Request': navigation.responseStart - navigation.requestStart,
'Response': navigation.responseEnd - navigation.responseStart,
'DOM Processing': navigation.domInteractive - navigation.domLoading,
'DOM Content Loaded': navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
'Page Load': navigation.loadEventEnd - navigation.loadEventStart
};
}
console.table(getNavigationTiming());
Практический пример: собственная библиотека метрик
class MetricsCollector {
constructor() {
this.metrics = {};
}
start(label) {
performance.mark(`${label}-start`);
}
end(label) {
performance.mark(`${label}-end`);
performance.measure(label, `${label}-start`, `${label}-end`);
const measure = performance.getEntriesByName(label)[0];
this.metrics[label] = measure.duration;
return measure.duration;
}
report() {
console.table(this.metrics);
}
clear() {
this.metrics = {};
performance.clearMarks();
performance.clearMeasures();
}
}
// Использование
const collector = new MetricsCollector();
collector.start('api-call');
await fetch('/api/data');
console.log('API call took:', collector.end('api-call'), 'ms');
collector.report();
Core Web Vitals - рекомендуемые значения
| Метрика | Хорошо | Требует улучшения | Плохо |
|---|---|---|---|
| LCP | < 2.5s | 2.5s - 4s | > 4s |
| FID | < 100ms | 100ms - 300ms | > 300ms |
| CLS | < 0.1 | 0.1 - 0.25 | > 0.25 |
Инструменты для анализа
// Google Web Vitals библиотека
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getFCP(console.log);
getLCP(console.log);
getTTFB(console.log);
Выводы
- Используй Performance API для измерения кастомных операций
- Мониторь Web Vitals для SEO и UX
- PerformanceObserver помогает отслеживать автоматически
- Chrome DevTools Performance tab для детального анализа
- Регулярно проверяй память и рендеринг
- Оптимизируй метрики, которые видит пользователь