На основе наблюдений я выделил 5 самых проблемных случая, когда JavaScript блокирует загрузку сайта.
Блокирующие скрипты
Часто на сайтах подключают скрипты из заблокированных соцсетей и сайтов. Это может быть:

Виджет соцсети, отображающий участников группы.
Подключение скрипта библиотеки для интеграции кнопки "Поделиться", который, в свою очередь, подключает скрипт запрещённой соцсети.
Скрипт авторизации через запрещённую соцсеть.
Доступ к этим соцсетям заблокирован через политику DENY, а не REJECT. Это значит, что браузер пользователя, отправит запрос на загрузку JavaScript файла и не получит ответа. Ожидание ответа будет "висеть" от 30 до 45 секунд. После этого браузер сбросит подключение.
Если скрипт загружается синхронно, а не асинхронно, то вызов события window.onload отложится на 30-45 секунд. Всё из-за того, что window.onload ожидает загрузку всех JavaScript файлов страницы, прежде чем отработать.
Поэтому следите, чтобы у вас не подключались файлы запрещённых соцсетей на сайте. Проверить их наличие можно 2 способами:
Отключить в своём браузере все плагины, блокирующие рекламу и защищающие от трекинга. Также отключить такую же защиту в настройках браузера. Открыть страницу и в инструментах разработчика проверить подвисшие скрипты.
Воспользуйтесь сервисом Сайт Аларм. Проверить наличие предупреждений в секции "Блокирующие файлы".
Тяжеловесные сервисы
Есть файлы,которые можно и нужно подключать по востребованию:

Каптчи. Общий объём файлов, загружаемой 1 каптчей около мегабайта. Правильным решением будет вызывать каптчу, в момент заполнения формы. То есть, когда вызывается событие focus у какого-либо поля.
Видео сервисы. Используйте фасады при отображении вставки видео в видеосервисов. Вот пример для youtube. Задача фасада отложить тяжеловесную загрузку кода плеера видео. При клике на видео, фасад подгружает код плеера. До этого момента фасад отображает только превью видео и кнопку плей.
Системы авторизации. Системы авторизации как VK ID или Yandex ID тяжеловесны. Но используются только на специальной странице входа либо во всплывающем окне. Подключайте скрипты систем авторизации отложено, в момент востребования, а не перманентно.
Карты. Если карты размещены на втором экране открываемой страницы и далее, то они становятся видны пользователю только после прокрутки страницы. Следовательно, нет смысла загружать их сразу. Лучше осуществлять их загрузку в событии 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 файлов

Все файлы на страницы подгружаются в порядке их объявления в HTML коде. Логично в первую очередь загрузить CSS файлы и картинки первого экрана страницы. Это нужно, чтобы как можно раньше показать пользователю хоть какой-нибудь контент. Это удержит его внимание и не даст ему шанса отвлечься или сменить вкладку.
Если подключить скрипты вначале, а затем CSS файлы, то страница будет белой несколько секунд. Первая графика отобразится только после загрузки всех JavaScript файлов в очереди.
Поэтому скрипты надо подключать перед закрывающим тегом </body>, а не в секции <head>.
Долгое выполнение JS

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

Чтобы бороться с этим, есть несколько способов:
Найдите "Узкое горлышко" с помощью профайлера. Профайлер firefox, профайлер chrome.
Подгружайте скрипты отложено. Уделите особое внимание тяжеловесным скриптам из одноимённого раздела этого поста.
Найдите неиспользуемые файлы. Отключите группировку JavaScript файлов в настройках сайта. Просканируйте ваш сайт в сервисе. Прокрутите к секции "Лишний JavaScript найден". Обратите внимание на файлы, у которых 90% кода не используется. Скорее всего, их подключения на странице можно избежать.
Почистите неиспользуемый JavaScript в уже существующих файлах. Как это сделать рассказано в этой статье.
Комментарии (21)

santjagocorkez
01.11.2025 20:36Системы авторизации как VK ID или Yandex ID
Требуется пример в виде картинки

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

santjagocorkez
01.11.2025 20:36Это очень простой запрос, я не знаю, как его ещё проще сформулировать.
Ответь на этот комментарий картинкой, на которой отображен(-ы) системы авторизации, указанные выше
Пожалуй, ещё проще уже невозможно.

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

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

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

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

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

subzey
01.11.2025 20:36Поэтому скрипты надо подключать перед закрывающим тегом , а не в секции .
Тут, похоже, парсер теги съел.
Если это про подключение скриптов перед закрывающим
<body>, то уж сильно дедовский метод. Лучше таки подключать их в<head>, но с атрибутомdeferи после стилей.
Так они пораньше начнут потихоньку грузиться по сети с приоритетом Low не дожидаясь того, как весь ответ html долетит целиком
Axenic Автор
01.11.2025 20:36Спасибо. Опечатку исправил.
Если загружать скрипты с аттрибутом
deferто они всё равно будут откладывать загрузку картинок, пускай и меньше. Плюс браузер паралельно может загружать только 6-8 файлов. Если скриптов много, то их загрузка заблокирует загрузку картинок.Размещая скрипты перед
</body>, мы управляем очередью загрузки скриптов. Метод дедовский, но альтернатив ему нет.
subzey
01.11.2025 20:36Может быть, это было актуально для HTTP/1.1, но с HTTP/2 браузер может загружать не меньше сотни ресурсов за раз, при этом у каждого запроса внутри коннекции есть приоритет.
Дефёрнутые скрипты грузятся с приоритетом Low
Стили — Highest
Картинки с Low пока не попадут во вьюпорт, после чего их приоритет динамически повышается до High.
Полная таблица тут: https://web.dev/articles/fetch-priorityПоэтому можно сильно не переживать, что кто-то у кого-то будет сильно канал отъедать. К тому же, через
fetchpriorityможно приоритет подтюнить. Например, если заведомо известно, что одна конкретная картинка будет показываться на первом экране, не грех ей поставитьfetchpriority=high
Axenic Автор
01.11.2025 20:36Управлять приоритетом выставляя атрибуты defer и fetchpriority теоретически можно. Но сформулировать какую-то простую и универсальную методику я не могу. Помещение скриптов в конец страницы фактически то же самое управление приоритетом загрузки. Оно интуитивно понятно и воспроизводимо даже начинающими кодерами в проектах любого уровня легаси бардака.
Defer и fetchpriority скорее подходят для тонкой поднастройки очереди загрузки при решении узких мест производительности, нежели для массового применения. При этом уже есть
<link rel="prefetch">и<img loading="lazy">. То есть, fetchpriority - не решает какую-то новую задачу, а является новой надстройкой. Из хорошего fetchpriority реализует новую парадигму мышления в вопросах очерёдности загрузки. Раньше очерёдность была привязана к порядку объявления объектов на странице, а сейчас к системе приоритетов, которой можно вручную управлять, выставляя атрибут fetchpriority.За ссылку на документацию по приоритету загрузки - огромное спасибо! Уже произвёл несколько тестов, теперь буду думать, как применять эту технологию на практике и доносить её до массового кодера. Прям реально полезный материал для размышлений.
Nexoic
Главный совет не используйте js если можно обойтись без него
divinity2000
Достаточно понимать что:
У браузера последовательный рендер
JS однопоточный
Больше проблем как таковых нет
Axenic Автор
Я бы ещё добавил, что событие window.onload - ключевое при загрузке страницы и всё что можно вызывать в нём или сразу после него, лучше так и сделать.
andreymal
Ключевое — DOMContentLoaded, обычно нет смысла ждать завершения загрузки всяких маловажных картинок
Axenic Автор
В DOMContentLoaded обычно вызываются инициализирующие скрипты. Например тот же jQuery(document).ready это событие DOMContentLoaded. Следовательно, если вы подключите какой-нибудь тяжеловесный картографический сервис, то он может отложить инициализацию плагина слайдера. Поэтому все сторонние сервисы, если они не на первом экране прокрутки расположены, нужно подключать именно в window.onload.
Vadiok
Такие штуки вообще часто имеет смысл подключать через intersection observer, когда пользователь доскроллит уже ближе к нужному элементу.
Axenic Автор
Верно. Я, например, когда каптчу подключаю на сайт, делаю это на событие onfocus любого из полей формы. Получается, что каптча грузится в момент когда пользователь начал ввод данных.
Axenic Автор
Есть ещё сторонние сервисы, вроде систем аналитики, каптч и карт. Они блокируют загрузку, если их неправильно вызывать.
Nexoic
Вроде как все системы аналитики хотят загружаться сразу чтоб отслеживать больше, да можно асинхронно чуть позже загрузить но это все такое
Axenic Автор
Они так пишут в своей документации. Но я читал об этом обсуждения и все сходятся во мнении что подключать рано их нет смысла. Единственное имеет смысл яндекс метрику подключать сразу, из-за её инструмента вебвизор, чтобы все действия пользователя успеть записать.
Все данные которые используют счётчики берутся из API браузера. Поведенческие данные, такие как скрол страницы у гугл аналитикс не обязательно прям на пол секунды раньше собирать.