На основе наблюдений я выделил 5 самых проблемных случая, когда JavaScript блокирует загрузку сайта.

Блокирующие скрипты

Часто на сайтах подключают скрипты из заблокированных соцсетей и сайтов. Это может быть:

Один из самых частых случаев блокировки загрузки страницы, это вот такой виджет facebook (соцсеть принадлежит компании Meta, признанной экстремистской в РФ).
Один из самых частых случаев блокировки загрузки страницы, это вот такой виджет facebook (соцсеть принадлежит компании Meta, признанной экстремистской в РФ).
  1. Виджет соцсети, отображающий участников группы.

  2. Подключение скрипта библиотеки для интеграции кнопки "Поделиться", который, в свою очередь, подключает скрипт запрещённой соцсети.

  3. Скрипт авторизации через запрещённую соцсеть.

Доступ к этим соцсетям заблокирован через политику DENY, а не REJECT. Это значит, что браузер пользователя, отправит запрос на загрузку JavaScript файла и не получит ответа. Ожидание ответа будет "висеть" от 30 до 45 секунд. После этого браузер сбросит подключение.

Если скрипт загружается синхронно, а не асинхронно, то вызов события window.onload отложится на 30-45 секунд. Всё из-за того, что window.onload ожидает загрузку всех JavaScript файлов страницы, прежде чем отработать.

Поэтому следите, чтобы у вас не подключались файлы запрещённых соцсетей на сайте. Проверить их наличие можно 2 способами:

  1. Отключить в своём браузере все плагины, блокирующие рекламу и защищающие от трекинга. Также отключить такую же защиту в настройках браузера. Открыть страницу и в инструментах разработчика проверить подвисшие скрипты.

  2. Воспользуйтесь сервисом Сайт Аларм. Проверить наличие предупреждений в секции "Блокирующие файлы".

Тяжеловесные сервисы

Есть файлы,которые можно и нужно подключать по востребованию:

Общий вес всех файлов гугл каптчи — 3.5 МБ. Подгружается она сразу, но используется только при непосредственной отправке формы.
Общий вес всех файлов гугл каптчи — 3.5 МБ. Подгружается она сразу, но используется только при непосредственной отправке формы.
  1. Каптчи. Общий объём файлов, загружаемой 1 каптчей около мегабайта. Правильным решением будет вызывать каптчу, в момент заполнения формы. То есть, когда вызывается событие focus у какого-либо поля.

  2. Видео сервисы. Используйте фасады при отображении вставки видео в видеосервисов. Вот пример для youtube. Задача фасада отложить тяжеловесную загрузку кода плеера видео. При клике на видео, фасад подгружает код плеера. До этого момента фасад отображает только превью видео и кнопку плей.

  3. Системы авторизации. Системы авторизации как VK ID или Yandex ID тяжеловесны. Но используются только на специальной странице входа либо во всплывающем окне. Подключайте скрипты систем авторизации отложено, в момент востребования, а не перманентно.

  4. Карты. Если карты размещены на втором экране открываемой страницы и далее, то они становятся видны пользователю только после прокрутки страницы. Следовательно, нет смысла загружать их сразу. Лучше осуществлять их загрузку в событии window.onload. Причём именно window.onload, а не jQuery(document).ready или DOMContentLoaded, чтобы в первую очередь загрузить всё полезное содержимое сайта.

Проверить слишком ранее подключение таких файлов можно в сервисе. Информация будет в разделах "Преждевременная загрузка файлов" и "Использование JS фасадов".

Счётчики аналитических систем

В документации счётчиков пишут, что их надо подключать в секции head как можно раньше. Но скрипты счётчиков увесистые и требует много процессорного времени на обработку. Да, сейчас все системы аналитики подгружают свои скрипты асинхронно, но из-за их размера они всё равно значительно откладывают загрузку страницы.

Счётчики могут отложить загрузку страницы от 0.15 до 0.5 секунд. Это притом, что страница должна загружаться за 1 секунду и быстрее.

Подключайте счётчики систем аналитики в событии window.onload. За исключением яндекс аналитики. Так как их инструмент вебвизор становится более полным, когда сбор информации о действиях пользователя начинается как можно раньше.

Вот так вот просто можно подключать счётчик гугла отложено. Достаточно обернуть его в функцию window.addEventListener("load", funcition() {}); и подгружать JavaScript через функцию (взята из счётчика яндекса).

<script>
window.addEventListener("load", function() {
    (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://www.googletagmanager.com/gtag/js?id=G-QWE123123", "ga");
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());

    gtag('config', 'G-QWE123123');
});
</script>

Вся статистическая информация об этапах загрузки страницы всё равно берётся из window.perfomance. Поэтому подключая счётчики отложено, вы вряд ли повлияете на наполнение итоговых отчётов.

Расположение вызова JS файлов

Загрузка всех изображений, расположенных после JavaScript, будет отложена.
Загрузка всех изображений, расположенных после JavaScript, будет отложена.

Все файлы на страницы подгружаются в порядке их объявления в HTML коде. Логично в первую очередь загрузить CSS файлы и картинки первого экрана страницы. Это нужно, чтобы как можно раньше показать пользователю хоть какой-нибудь контент. Это удержит его внимание и не даст ему шанса отвлечься или сменить вкладку.

Если подключить скрипты вначале, а затем CSS файлы, то страница будет белой несколько секунд. Первая графика отобразится только после загрузки всех JavaScript файлов в очереди.

Поэтому скрипты надо подключать перед закрывающим тегом </body>, а не в секции <head>.

Долгое выполнение JS

Профайлер выглядит нагружено. Но на самом деле разобраться в нём можно за 1 день.
Профайлер выглядит нагружено. Но на самом деле разобраться в нём можно за 1 день.

Различные объёмные JavaScript файлы могут занимать длительное время на интерпретацию (аналог компиляции в JS). Также, JavaScript файлы могут попросту долго отрабатывать.

Файл 495972ac.js используется на 10%. Скорее вызывается только функция инициализации плагина, а сам функционал не используется.
Файл 495972ac.js используется на 10%. Скорее вызывается только функция инициализации плагина, а сам функционал не используется.

Чтобы бороться с этим, есть несколько способов:

  1. Найдите "Узкое горлышко" с помощью профайлера. Профайлер firefox, профайлер chrome.

  2. Подгружайте скрипты отложено. Уделите особое внимание тяжеловесным скриптам из одноимённого раздела этого поста.

  3. Найдите неиспользуемые файлы. Отключите группировку JavaScript файлов в настройках сайта. Просканируйте ваш сайт в сервисе. Прокрутите к секции "Лишний JavaScript найден". Обратите внимание на файлы, у которых 90% кода не используется. Скорее всего, их подключения на странице можно избежать.

  4. Почистите неиспользуемый JavaScript в уже существующих файлах. Как это сделать рассказано в этой статье.

Комментарии (21)


  1. Nexoic
    01.11.2025 20:36

    Главный совет не используйте js если можно обойтись без него


    1. divinity2000
      01.11.2025 20:36

      Достаточно понимать что:

      • У браузера последовательный рендер

      • JS однопоточный

      Больше проблем как таковых нет


      1. Axenic Автор
        01.11.2025 20:36

        Я бы ещё добавил, что событие window.onload - ключевое при загрузке страницы и всё что можно вызывать в нём или сразу после него, лучше так и сделать.


        1. andreymal
          01.11.2025 20:36

          Ключевое — DOMContentLoaded, обычно нет смысла ждать завершения загрузки всяких маловажных картинок


          1. Axenic Автор
            01.11.2025 20:36

            В DOMContentLoaded обычно вызываются инициализирующие скрипты. Например тот же jQuery(document).ready это событие DOMContentLoaded. Следовательно, если вы подключите какой-нибудь тяжеловесный картографический сервис, то он может отложить инициализацию плагина слайдера. Поэтому все сторонние сервисы, если они не на первом экране прокрутки расположены, нужно подключать именно в window.onload.


            1. Vadiok
              01.11.2025 20:36

              Такие штуки вообще часто имеет смысл подключать через intersection observer, когда пользователь доскроллит уже ближе к нужному элементу.


              1. Axenic Автор
                01.11.2025 20:36

                Верно. Я, например, когда каптчу подключаю на сайт, делаю это на событие onfocus любого из полей формы. Получается, что каптча грузится в момент когда пользователь начал ввод данных.


    1. Axenic Автор
      01.11.2025 20:36

      Есть ещё сторонние сервисы, вроде систем аналитики, каптч и карт. Они блокируют загрузку, если их неправильно вызывать.


      1. Nexoic
        01.11.2025 20:36

        Вроде как все системы аналитики хотят загружаться сразу чтоб отслеживать больше, да можно асинхронно чуть позже загрузить но это все такое


        1. Axenic Автор
          01.11.2025 20:36

          Они так пишут в своей документации. Но я читал об этом обсуждения и все сходятся во мнении что подключать рано их нет смысла. Единственное имеет смысл яндекс метрику подключать сразу, из-за её инструмента вебвизор, чтобы все действия пользователя успеть записать.

          Все данные которые используют счётчики берутся из API браузера. Поведенческие данные, такие как скрол страницы у гугл аналитикс не обязательно прям на пол секунды раньше собирать.


  1. santjagocorkez
    01.11.2025 20:36

    Системы авторизации как VK ID или Yandex ID

    Требуется пример в виде картинки


    1. Axenic Автор
      01.11.2025 20:36

      Пример, который вы требуете, что должен проиллюстрировать? Системы авторизации надо подключать во время открытия всплывающего окна авторизации. Вот нажал пользователь на кнопку "Войти" в этот момент всплывает форма с вводом логина и пароля, а так же подгружаются сервисы авторизации. Пользователи пользуются формой авторизации на сайте с частотой меньше 0.5% и подгружать их сразу и на каждой странице - нерентабельно.


      1. santjagocorkez
        01.11.2025 20:36

        Это очень простой запрос, я не знаю, как его ещё проще сформулировать.

        Ответь на этот комментарий картинкой, на которой отображен(-ы) системы авторизации, указанные выше

        Пожалуй, ещё проще уже невозможно.


        1. Axenic Автор
          01.11.2025 20:36

          Просто запрос действительно настолько простой. Сервисы популярные и встречаются на каждом втором сайте. Поэтому подумал, что я неправильно понял.

          VK ID
          VK ID
          Yandex ID
          Yandex ID

          Вот документация яндекс и ВК. Вот такие скрипты надо подгружать только по требованию, например когда открывается всплывающее окно авторизации.


          1. santjagocorkez
            01.11.2025 20:36

            Это не авторизация. Это аутентификация. Авторизация — это про «принципалу такому-то разрешается (с)делать это, это и это». Например, вход на сайт через ЕСИА (госуслуги) после экрана аутентификации показывает второй экран, мол, «сайт такой-то хочет получить доступ к информации о паспортных данных, номерах телефонов, разрешить?». Вот этот второй экран и есть авторизация.


            1. Axenic Автор
              01.11.2025 20:36

              В документации яндекса и ВК (ссылки в предыдущем комментарии) называется авторизация.


              1. santjagocorkez
                01.11.2025 20:36

                Совсем не повод повторять за безграмотными составителями документации.


  1. subzey
    01.11.2025 20:36

    Поэтому скрипты надо подключать перед закрывающим тегом , а не в секции .

    Тут, похоже, парсер теги съел.

    Если это про подключение скриптов перед закрывающим <body>, то уж сильно дедовский метод. Лучше таки подключать их в <head>, но с атрибутом defer и после стилей.
    Так они пораньше начнут потихоньку грузиться по сети с приоритетом Low не дожидаясь того, как весь ответ html долетит целиком


    1. Axenic Автор
      01.11.2025 20:36

      Спасибо. Опечатку исправил.

      Если загружать скрипты с аттрибутомdefer то они всё равно будут откладывать загрузку картинок, пускай и меньше. Плюс браузер паралельно может загружать только 6-8 файлов. Если скриптов много, то их загрузка заблокирует загрузку картинок.

      Размещая скрипты перед </body> , мы управляем очередью загрузки скриптов. Метод дедовский, но альтернатив ему нет.


      1. subzey
        01.11.2025 20:36

        Может быть, это было актуально для HTTP/1.1, но с HTTP/2 браузер может загружать не меньше сотни ресурсов за раз, при этом у каждого запроса внутри коннекции есть приоритет.

        Дефёрнутые скрипты грузятся с приоритетом Low
        Стили — Highest
        Картинки с Low пока не попадут во вьюпорт, после чего их приоритет динамически повышается до High.
        Полная таблица тут: https://web.dev/articles/fetch-priority

        Поэтому можно сильно не переживать, что кто-то у кого-то будет сильно канал отъедать. К тому же, через fetchpriority можно приоритет подтюнить. Например, если заведомо известно, что одна конкретная картинка будет показываться на первом экране, не грех ей поставить fetchpriority=high


        1. Axenic Автор
          01.11.2025 20:36

          Управлять приоритетом выставляя атрибуты defer и fetchpriority теоретически можно. Но сформулировать какую-то простую и универсальную методику я не могу. Помещение скриптов в конец страницы фактически то же самое управление приоритетом загрузки. Оно интуитивно понятно и воспроизводимо даже начинающими кодерами в проектах любого уровня легаси бардака.

          Defer и fetchpriority скорее подходят для тонкой поднастройки очереди загрузки при решении узких мест производительности, нежели для массового применения. При этом уже есть <link rel="prefetch"> и <img loading="lazy">. То есть, fetchpriority - не решает какую-то новую задачу, а является новой надстройкой. Из хорошего fetchpriority реализует новую парадигму мышления в вопросах очерёдности загрузки. Раньше очерёдность была привязана к порядку объявления объектов на странице, а сейчас к системе приоритетов, которой можно вручную управлять, выставляя атрибут fetchpriority.

          За ссылку на документацию по приоритету загрузки - огромное спасибо! Уже произвёл несколько тестов, теперь буду думать, как применять эту технологию на практике и доносить её до массового кодера. Прям реально полезный материал для размышлений.