Фронтенд — это то, что видит пользователь: интерфейс сайта или веб-приложения. А производительность фронтенда — это скорость, с которой сайт или веб-приложение загружается и реагирует на действия пользователя. Чем быстрее и отзывчивее работает интерфейс, тем удобнее им пользоваться. Сегодня посмотрим, что влияет на производительность и скорость загрузки и как это можно оптимизировать.
Ответ сервера
Когда мы открываем любой сайт, браузер устанавливает соединение с сервером, на котором этот сайт расположен. При этом браузер запрашивает HTML-код страницы, а если код ссылается на ещё какие-то файлы, то браузер загружает и их тоже — это могут быть файлы CSS, JavaScript и изображения. Перед тем как показать нам финальный результат отрисовки страницы, браузер делает следующее:
- Строит DOM, или Document Object Model, — дерево из HTML-кода. Это структура, которая отражает все компоненты страницы.
- Строит CSSOM, или CSS Object Model, — дерево из CSS-кода. Это структура со всеми стилями сайта.
На этом этапе производительность — это то, насколько быстро от сервера приходит ответ и как быстро начинают загружаться все нужные файлы. Эта скорость влияет на пользовательский опыт, конверсию и SEO.
Для оценки производительности при загрузке страницы используют показатель TTFB, или Time to First Byte, — так называют время от отправки запроса на сервер до получения от него первого байта ответа. TTFB можно измерить с помощью инструмента PageSpeed.
На скорость ответа сервера влияет общее число HTTP/HTTPS-запросов. Файлы CSS, скриптов, шрифтов, изображений и всего остального запрашиваются по отдельности. Чем больше запросов, тем дольше браузер загружает все ресурсы страницы.
Как оптимизировать: чтобы сократить скорость ответа сервера, уменьшают количество запросов. Для этого объединяют небольшие CSS- и JavaScript-файлы и проводят минификацию файлов для уменьшения их размера — удаляют из кода лишние символы, например пробелы, комментарии и новые строки.
Чтобы при повторных посещениях сайта браузер не запрашивал и не скачивал содержимое заново, в файле .htaccess настраивают кэширование. При этом браузер проверяет, какие файлы у него уже есть, и загружает их из локального хранилища. Это уменьшает количество запросов к серверу.
Рендеринг страницы
После того как браузер получил данные от сервера, он с помощью DOM и CSSOM делает рендер страницы — отрисовывает её на экране. На скорость рендеринга страницы влияет в первую очередь сложность DOM-дерева и стилей.
Есть несколько показателей, которые определяют, насколько быстро страница отрисовалась и готова к использованию:
- First Paint — момент, когда на экране впервые появляется что-то визуальное, например фон или обводка. Этот показатель определяет, насколько быстро начинается процесс рендеринга после получения данных.
- First Contentful Paint — момент, когда на странице появляется первый смысловой контент: текст или изображение.
- Largest Contentful Paint — момент, когда на странице появляется самый большой элемент содержимого. С помощью этого показателя оценивают воспринимаемую скорость загрузки, поскольку большие элементы — это часто основной фокус внимания пользователя.
На скорость рендеринга страницы влияет сложность DOM. Сложный DOM увеличивает объём данных, необходимых для передачи, и это замедляет загрузку.
Как оптимизировать: уменьшать количество элементов в DOM, а если это невозможно, то упрощать стили. Также используют подход «критический CSS»: подключают в начало страницы только те стили, которые нужны для отрисовки её видимой части.
Когда браузер обнаруживает в HTML ссылку на CSS-файл, то останавливает обработку HTML до тех пор, пока не загрузит и не обработает CSS. Это необходимо, чтобы перед отображением страницы точно знать, как она должна выглядеть. Но такая загрузка может замедлить отображение контента. С «критическим CSS» браузер может быстрее отобразить содержимое, поскольку количество данных для загрузки и обработки сокращается.
Загрузка изображений
Загрузка изображений происходит так:
- Получив HTML-документ с сервера, браузер начинает парсить его содержимое.
- В процессе парсинга браузер обнаруживает теги
<img>
и другие элементы со ссылками на изображения. - Для каждого найденного изображения браузер отправляет запрос по указанному адресу источника.
- Сервер обрабатывает эти запросы и возвращает бинарные данные изображений.
- По мере загрузки данных браузер декодирует их и показывает изображения на странице. Если они много весят или интернет медленный, изображения могут загружаться и отображаться по частям.
На скорость загрузки изображений влияют их количество, формат и методы загрузки. Чем больше изображений и их вес, тем ниже скорость загрузки и производительность.
Как оптимизировать: используют сжатие и оптимизацию изображений, ленивую загрузку и асинхронное декодирование. Google рекомендует использовать форматы WebP и AVIF, которые дают лучшее сжатие при сохранении высокого качества изображений. Ленивая загрузка позволяет откладывать загрузку изображений вне области видимости пользователя. Проще говоря, пока пользователь не дошёл до картинок, которые сразу не видны, браузер их не загружает (или загружает в фоне). Асинхронное декодирование состоит в том, что браузер в фоновом режиме обрабатывает и преобразует изображения в формат, готовый к отображению на экране.
Для этого в HTML-коде прописывают специальные атрибуты:
<img class="main-widget-post__thumbnail" src="https://thecode.media/wp content/uploads/2024/04/1-3-1-320x224.png" alt="Как разработчику правильно просить обратную связь" decoding='async' loading='lazy'>
Атрибут loading="lazy"
активирует ленивую загрузку.
Атрибут decoding="async"
позволяет браузеру декодировать изображения в асинхронном режиме. Это ускоряет загрузку страницы, поскольку браузер может продолжать обрабатывать другие задачи, пока декодируется изображение.
⚠️ Ленивую загрузку не используют для тех изображений, которые должны быть видны сразу же при открытии страницы.
Ещё один способ оптимизации: использовать адаптивные изображения. Это значит, что для каждого конкретного устройства изображение будет отображаться в наиболее подходящем разрешении и размере.
HTML-код в этом случае будет выглядеть так:
<picture>
<source media="(min-width: 800px)" srcset="large.webp">
<source media="(min-width: 500px)" srcset="medium.webp">
<img src="small.webp" alt="Адаптивная картинка">
</picture>
В этом примере для экранов шире 800 пикселей загрузится изображение large.webp, для экранов от 500 пикселей — medium.webp, а для более мелких экранов или в случаях, когда браузер не поддерживает элемент <picture>
, используется small.webp.
Интерактивность: выполнение JS-скриптов
В зависимости от того, как скрипты внедрены в HTML-код, их загрузка может начинаться в разные моменты рендеринга страницы и влиять на общую производительность. Скрипты, размещённые в теле страницы, загружаются и выполняются в момент их обнаружения браузером.
Если скрипты размещены в <head>
страницы и не имеют атрибутов async
или defer
, то их загрузка и выполнение начинается сразу же после обнаружения браузером. При этом браузер останавливает парсинг HTML, пока скрипт не будет загружен и выполнен. Скрипты с атрибутом async
загружаются и выполняются сразу после обнаружения, но дальнейший разбор HTML не блокируется. Скрипты с атрибутом defer
также начинают загружаться сразу, но их выполнение откладывается до тех пор, пока браузер не распарсит весь HTML.
Влияние JavaScript на производительность страницы проверяют с помощью Lighthouse и DevTools (инструментов разработчика). Производительность загрузки и выполнения скриптов в Lighthouse измеряется метрикой Time to Interactive (TTI).
На скорость выполнения JS-скриптов влияют их размер и сложность, расположение в коде и атрибуты. Большие и сложные скрипты требуют больше времени на загрузку и выполнение.
Как оптимизировать: чтобы скрипты загружались и обрабатывались быстрее, разработчики разбивают JS-код на небольшие фрагменты. Это уменьшает первоначальную нагрузку JS на странице, поскольку загружаются только критичные части кода. Оставшийся код загружается по мере необходимости, например, при взаимодействии пользователя с определёнными элементами интерфейса.
Атрибуты async
и defer
позволяют задавать порядок загрузки и выполнения. Это особенно важно при загрузке скриптов, которые не нужны для первоначального отображения страницы.
Для обработки тяжёлых задач в фоновом режиме используют Web Workers. Этот механизм позволяет выполнять скрипты параллельно с основным потоком, который обычно занят обработкой пользовательского интерфейса.
Как разрабатывать сайты оптимально
Чтобы упростить разработку и оптимизировать производительность, фронтендеры используют фреймворки и библиотеки: React, Angular, Vue.js, Svelte и другие. Они предоставляют готовые компоненты и утилиты для разработки интерфейса и логики веб-приложений.
Например, в React и Vue.js используется виртуальный DOM. Это копия реального DOM сайта, которая хранится в оперативной памяти, а не в браузере. Если на страницу нужно внести изменения, то их сначала применяют к виртуальному DOM, а не к реальному. Это сокращает время, необходимое для обновления интерфейса, и улучшает производительность, особенно при высоких нагрузках.