Веб-разработка
Производительность фронтенда
Исследование Google: каждые 100мс улучшения скорости загрузки = +1% конверсии. Amazon: задержка 100мс = -1% выручки. Pinterest: сокращение времени загрузки на 40% = +15% регистраций. Производительность фронтенда - не техническая метрика, это бизнес-показатель.
- **Google** использует Core Web Vitals как ranking signal с 2021 года - медленные сайты теряют позиции в поиске
- **Shopify** сообщил о 35% улучшении конверсии после перехода на статически генерируемые страницы с агрессивным кешированием
- **Twitter Lite** с code splitting и Service Worker: 30% снижение bounce rate на медленных сетях в развивающихся рынках
Core Web Vitals: LCP, CLS, INP
Google измеряет «качество пользовательского опыта» тремя метриками, которые влияют на SEO-ранжирование. **Core Web Vitals** - не абстрактные числа: каждая метрика измеряет конкретный раздражающий пользователя сценарий.
**LCP (Largest Contentful Paint)** - когда виден главный контент (изображение, заголовок). Хорошо: до 2.5с. **CLS (Cumulative Layout Shift)** - насколько контент «прыгает» при загрузке. Хорошо: < 0.1. **INP (Interaction to Next Paint)** - задержка между кликом пользователя и обновлением UI. Хорошо: < 200мс.
**Инструменты:** Chrome DevTools (Lighthouse), PageSpeed Insights, Web Vitals extension. Важно: Lab data (Lighthouse) ≠ Field data (реальные пользователи). Google Search Console показывает реальный CWV по вашему сайту.
Изображение на странице прыгает вниз когда загружается баннер выше. Какой Core Web Vital нарушается?
Lazy Loading и Intersection Observer
Страница загружает 30 изображений, из которых пользователь видит только первые 3. Остальные 27 потребляют bandwidth и замедляют загрузку - зря. **Lazy Loading** откладывает загрузку ресурсов до момента, когда они нужны: изображений - до появления в viewport, компонентов - до первого использования.
**Intersection Observer API** - нативный способ отслеживать появление элемента во viewport. Раньше это делали через `scroll` event + `getBoundingClientRect()` - дорого (layout thrashing). Intersection Observer работает асинхронно, не блокирует main thread.
**LCP изображение не должно быть lazy!** Hero изображение вверху страницы - это часто LCP элемент. Если добавить `loading="lazy"` - браузер откладывает его загрузку и LCP растёт. Правило: `loading="lazy"` только для изображений ниже fold.
Почему Intersection Observer лучше scroll event для lazy loading?
Code Splitting и dynamic import
Webpack собирает весь JS в один bundle. 2MB JavaScript грузится, парсится и выполняется даже для пользователей, которые зашли только на главную страницу и никогда не откроют настройки. **Code Splitting** разбивает bundle на чанки, которые загружаются только когда нужны.
**Dynamic import** - ключевой инструмент: `import()` возвращает Promise и является точкой разрыва бандла. Webpack/Vite автоматически выносят динамически импортируемый модуль в отдельный чанк. Route-based splitting в Next.js делает это автоматически для каждой страницы.
**Оптимальный размер чанка:** 50-150KB после gzip для первоначально загружаемых чанков. Слишком много мелких чанков = много HTTP запросов (при HTTP/1.1). Слишком крупные = долгий parse. HTTP/2 multiplexing снижает стоимость дополнительных запросов.
Пользователь открывает главную страницу. Модальное окно настроек открывается в 5% случаев. Code splitting для настроек:
HTTP Caching и Service Workers
Лучший сетевой запрос - тот, которого нет. **HTTP кеширование** позволяет браузеру повторно использовать ранее загруженные ресурсы. Правильно настроенный кеш - это разница между «страница загружается за 3 секунды» и «страница мгновенная для повторных посещений».
**Service Worker** - это прокси-сервер в браузере: перехватывает сетевые запросы и может вернуть ответ из кеша. В отличие от HTTP кеша (только GET, управляется сервером), Service Worker может кешировать POST, динамически выбирать стратегию, работать офлайн.
**Cache busting:** при деплое нового кода старые файлы в кеше браузера остаются. Решение - включать contenthash в имя файла (`main.a1b2c3.js`). Webpack/Vite делают это автоматически. HTML-документ не кешируется жёстко - он всегда ссылается на актуальные hash-имена ассетов.
100% score в Lighthouse означает отличный пользовательский опыт в реальности.
Lighthouse - lab measurement в идеальных условиях. Реальные Core Web Vitals от Chrome User Experience Report (CrUX) отличаются: медленные устройства, нестабильный мобильный интернет.
Lighthouse запускается на мощном ноутбуке с быстрым интернетом. P75 реальных пользователей - совсем другие условия. Оптимизируйте по Field Data из Search Console.
JS bundle деплоится с именем `main.js` (без hash). При деплое нового кода пользователи получат:
Производительность фронтенда
- CWV: LCP < 2.5с (главный контент), CLS < 0.1 (стабильность), INP < 200мс (отклик) - влияют на SEO
- Lazy loading: loading='lazy' для below-fold изображений; Intersection Observer для кастомной логики; hero изображение НЕ lazy
- Code splitting: React.lazy + dynamic import выносит код в отдельный chunk; загружается только при использовании
- HTTP кеш: immutable assets с contenthash кешируются вечно; HTML no-cache; Service Worker для offline + сложных стратегий
Связанные темы
Производительность фронтенда тесно связана с рендерингом и сетевым стеком:
- SSR и SSG: Next.js — Streaming SSR улучшает LCP и TTFB напрямую
- HTTP и CDN — CDN + правильный Cache-Control - основа быстрой доставки ассетов
- Progressive Web Apps — Service Worker - основа PWA offline-возможностей
Вопросы для размышления
- Как определить приоритет оптимизаций - с чего начать: LCP, CLS или INP?
- При каких обстоятельствах aggressive caching может навредить пользователям и как защититься?
- Чем отличается оптимизация для первого посещения и для повторных - и нужно ли приоритизировать одно над другим?