Performance Metrics: Core Web Vitals
Google Core Web Vitals (LCP, INP, CLS) стали официальными сигналами ранжирования с 2021–2024 гг.; умение объяснить каждую метрику, измерить её в коде и предложить конкретные оптимизации — обязательный навык TechLead в компаниях с серьёзным вниманием к production-перформансу.
// Core Web Vitals: порог Good/Needs Improvement/Poor (75-й перцентиль пользователей)//// Метрика Что измеряет Good Poor// ─────── ──────────────────────────────────── ──────── ──────// LCP Largest Contentful Paint (загрузка) <= 2.5s > 4s// INP Interaction to Next Paint (отклик) <= 200ms > 500ms// CLS Cumulative Layout Shift (стабильность) <= 0.1 > 0.25// TTFB Time to First Byte (сервер) <= 800ms > 1800ms// FCP First Contentful Paint <= 1.8s > 3s//// FID (First Input Delay) заменён на INP в марте 2024 —// INP учитывает ВСЕ взаимодействия, не только первое.
// Измерение через web-vitals (Google, ~2 КБ gzip)import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals';
function sendToAnalytics({ name, value, rating, id }) { navigator.sendBeacon('/analytics', JSON.stringify({ name, value, rating, id }));}onLCP(sendToAnalytics);onINP(sendToAnalytics);onCLS(sendToAnalytics); // накапливается, отправляется при unload// PerformanceObserver: низкоуровневый API браузераconst po = new PerformanceObserver(list => { for (const entry of list.getEntries()) { console.log(entry.entryType, entry.name, (entry.duration ?? entry.startTime).toFixed(1)); }});po.observe({ type: 'largest-contentful-paint', buffered: true });po.observe({ type: 'layout-shift', buffered: true });po.observe({ type: 'first-input', buffered: true });po.observe({ type: 'longtask', buffered: true }); // > 50ms блокирует INP
// Поиск Long Tasks (виновники плохого INP)new PerformanceObserver(list => { for (const t of list.getEntries()) { if (t.duration > 50) { console.warn(`Long task: ${t.duration.toFixed(0)}ms`, { startTime: t.startTime, attribution: t.attribution, }); } }}).observe({ type: 'longtask' });
// Navigation Timing (TTFB, DOMContentLoaded, load)const [nav] = performance.getEntriesByType('navigation');console.log('TTFB:', nav.responseStart - nav.requestStart);console.log('DOMContentLoaded:', nav.domContentLoadedEventEnd - nav.fetchStart);// Оптимизации под каждую метрику
// LCP: preload hero-image, fetchpriority// <link rel="preload" as="image" href="/hero.webp" fetchpriority="high">// <img src="/hero.webp" fetchpriority="high" width="1200" height="600">// Избегайте: lazy-loading hero image, render-blocking fonts/scripts
// INP: разбивать длинные задачи через scheduler.yield()async function processLargeList(items) { const CHUNK = 100; for (let i = 0; i < items.length; i++) { process(items[i]); if (i % CHUNK === 0 && i > 0) { // Scheduler API (Chrome 115+) или fallback await (typeof scheduler !== 'undefined' && scheduler.yield ? scheduler.yield() : new Promise(r => setTimeout(r, 0))); } }}
// CLS: резервировать размеры для медиа (избегать layout shift)// <img width="800" height="600" src="photo.jpg"> <!-- браузер резервирует место -->// CSS: aspect-ratio: 16 / 9; /* до загрузки */// Виновники CLS: font swap, динамические баннеры без min-height, lazy images без размеровИтог: LCP (загрузка), INP (интерактивность), CLS (стабильность) — метрики пользовательского опыта с прямым влиянием на SEO и конверсию; измеряйте на реальных устройствах (RUM).