JavaScript — это основной инструмент для создания интерактивных веб-сайтов, но он также является “тормозом” для производительности. По умолчанию, когда браузер встречает тег <script>, он вынужден остановить парсинг HTML-документа, загрузить, скомпилировать и выполнить весь скрипт. Этот механизм, известный как блокировка рендеринга (render-blocking), критически замедляет загрузку и интерактивность страницы, уничтожая показатели LCP (Largest Contentful Paint) и INP (Interaction to Next Paint).

Наша задача — перевести как можно больше JS в асинхронный режим, чтобы разгрузить главный поток (Main Thread) браузера и позволить ему быстро отобразить контент.

1. Понимание проблемы: Блокирующий JavaScript

Традиционный тег <script> помещается в очередь выполнения главного потока. Пока браузер выполняет этот JS, он не может:

  1. Обработать остальной HTML.
  2. Загрузить, обработать или отобразить CSS.
  3. Ответить на действия пользователя (клики, прокрутку).

Это приводит к длительному Времени Блокировки (Total Blocking Time, TBT), что напрямую влияет на метрику INP и снижает оценку PageSpeed.

2. Главные инструменты: Атрибуты async и defer

Атрибуты async и defer позволяют браузеру загружать скрипты параллельно с парсингом HTML, устраняя блокировку рендеринга. Выбор между ними зависит от того, насколько скрипты зависят от порядка выполнения и от DOM.

2.1. Атрибут async

Используйте async, когда скрипт не зависит от других скриптов и не зависит от готового DOM-дерева.

Как работает:

  1. Загрузка: Начинается параллельно с парсингом HTML.
  2. Выполнение: Как только скрипт загружен, парсинг HTML приостанавливается, скрипт выполняется, и только после этого парсинг продолжается.

Применение: Идеально подходит для независимых скриптов, таких как:

  • Счетчики аналитики (Google Analytics, Яндекс.Метрика).
  • Виджеты социальных сетей (если они не критичны для первого экрана).
  • Асинхронные рекламные скрипты.
<script async src="analytics.js"></script>
<script async src="ads-script.js"></script>

2.2. Атрибут defer

Используйте defer, когда скрипт зависит от других скриптов или ему требуется готовое DOM-дерево для работы (т.е., он манипулирует элементами страницы).

Как работает:

  1. Загрузка: Начинается параллельно с парсингом HTML.
  2. Выполнение: Скрипты выполняются только после завершения парсинга всего HTML, но до срабатывания события DOMContentLoaded. Скрипты с defer выполняются в том порядке, в котором они указаны в документе.

Применение: Идеально подходит для:

  • Ваших основных скриптов приложения.
  • Библиотек, зависящих от DOM (например, обработчики форм, модальных окон).
  • Скриптов, имеющих строгий порядок зависимости.
<!-- Сначала должен загрузиться jQuery, потом app.js -->
<script defer src="vendor/jquery.js"></script>
<script defer src="app.js"></script> 

Сравнительная таблица

АтрибутЗагрузкаПарсинг HTMLВыполнениеГарантия порядкаРекомендация
НетБлокируетПриостанавливаетсяНемедленноДаИзбегать!
asyncПараллельноПриостанавливаетсяНемедленно после загрузкиНетНезависимые скрипты.
deferПараллельноПродолжаетсяПосле парсинга HTML, перед DOMContentLoadedДаЗависимые скрипты и логика приложения.

3. Приоритизация и отложенная загрузка некритичного JS

Даже после использования async и defer у вас могут остаться скрипты, которые не нужны пользователю сразу. Их следует загружать только при необходимости.

3.1. Динамический импорт и Code Splitting

Для современных веб-приложений (React, Angular, Vue) наиболее эффективным подходом является разделение кода (Code Splitting), основанное на динамическом импорте (import()).

Это позволяет загружать код для отдельных маршрутов, модальных окон или редких функций только в момент, когда они активируются пользователем.

Пример (псевдокод):

// Код для формы обратной связи не загружается сразу.
document.getElementById('feedback-button').addEventListener('click', () => {
  // Загрузка кода происходит только при клике
  import('./feedback-form.js')
    .then(module => {
      module.initForm();
    })
    .catch(error => console.error('Ошибка загрузки формы:', error));
});

Динамический импорт кардинально снижает TBT и улучшает INP, поскольку из главного бандла JS удаляются сотни килобайт кода, который не нужен при первой загрузке.

3.2. Использование Web Workers для разгрузки главного потока

Сложные, ресурсоемкие вычисления (например, парсинг больших JSON-файлов, интенсивная обработка данных) должны быть вынесены из главного потока браузера в Web Workers.

Web Workers — это фоновые потоки, которые не имеют доступа к DOM, но могут выполнять тяжелые вычисления, не блокируя пользовательский интерфейс.

Ключевой эффект: Перенося работу в Web Workers, вы напрямую уменьшаете занятость главного потока, что является лучшей гарантией быстрого INP.

4. Оптимизация загрузки сторонних скриптов

Сторонние скрипты (реклама, виджеты, чаты, аналитика) часто не поддаются вашему контролю и могут потреблять огромное количество ресурсов.

4.1. Ленивая загрузка (Lazy Loading) виджетов

Если на странице есть чат, виджет погоды или другие внешние элементы, которые не нужны сразу:

  • Отложите их загрузку: Используйте JS для создания тега <script> и его добавления в DOM через 2-5 секунд после загрузки страницы или после того, как пользователь начал скроллить.
  • Ограничение по взаимодействию: Загружайте скрипт чата только после первого взаимодействия пользователя со страницей (например, после первого клика).

4.2. Использование preconnect для сторонних CDN

Как и в случае со шрифтами, используйте preconnect для доменов сторонних скриптов, чтобы минимизировать задержку установки соединения.

<!-- Предварительно устанавливаем соединение с CDN рекламной сети -->
<link rel="preconnect" href="[https://example-ads.com](https://example-ads.com)">

Вывод

Для достижения 100 баллов в Google PageSpeed Insights, относитесь к JavaScript как к дефицитному ресурсу.

  1. Критичный JS: Используйте defer для выполнения в правильном порядке после парсинга HTML.
  2. Некритичный JS (Аналитика): Используйте async.
  3. Необязательный JS (Виджеты, Модальные окна): Используйте динамический импорт или отложенную загрузку по таймеру/событию.
  4. Тяжелые вычисления: Переносите их в Web Workers.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *