Вы написали красивый JavaScript-код, но сайт грузится медленно. Кнопки не работают, пока не загрузится весь скрипт. Пользователи уходят. Проблема не в коде - она в месте подключения скриптов HTML. Многие новички копируют примеры из интернета и вставляют скрипты прямо в <head>, не задумываясь, что это ломает отображение страницы. Давайте разберёмся, где и как правильно подключать скрипты, чтобы сайт работал быстро и предсказуемо.
Почему место подключения скриптов так важно
Когда браузер встречает тег <script> в HTML, он останавливает парсинг страницы. Даже если скрипт маленький - он блокирует отрисовку всего, что идёт после него. Это называется blocking. Если вы положили скрипт в начало <head>, пользователь увидит пустой экран, пока браузер не скачает, распарсит и выполнит ваш JS. Это может занять 2-5 секунд на медленном соединении. А если скрипт большой или лежит на медленном сервере - пользователь просто закроет вкладку.
Сравните: если вы пришли в магазин, а кассир сначала ушёл за тележкой, потом за корзинкой, потом за продавцом, чтобы всё проверить - вы уйдёте. Так же и с сайтом. Пользователь хочет видеть контент сразу, а не ждать, пока загрузится кнопка «Поделиться в ВК».
Где размещать скрипты: три основных варианта
Есть три места, куда можно вставить <script> - и каждое имеет свои плюсы и минусы.
1. Внутри <head> - не лучший выбор
Так делают по привычке. Многие шаблоны CMS и старые учебники предлагают именно так. Но это вредно для производительности. Если скрипт не критичен для отрисовки (например, аналитика, реклама, модальные окна), он просто тормозит загрузку.
Исключение - скрипты, которые должны запуститься до отрисовки страницы: например, шифрование данных, загрузка кастомных шрифтов через font-display, или скрипты, которые меняют стили до того, как пользователь их увидит. В таких случаях используйте defer или async.
2. Перед закрывающим тегом </body> - лучший вариант для большинства случаев
Это стандарт, который рекомендуют Google, Mozilla и все крупные фронтенд-команды. Скрипт загружается после того, как браузер уже отрисовал HTML и CSS. Пользователь видит содержимое страницы, а скрипт подгружается фоном. Никаких задержек. Никаких пустых экранов.
Пример правильной структуры:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Мой сайт</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Добро пожаловать</h1>
<p>Этот текст виден сразу.</p>
<script src="main.js"></script>
</body>
</html>
Такой подход работает для 90% сайтов. Даже если скрипт большой - он не мешает пользователю начать взаимодействовать с контентом.
3. С атрибутами async и defer - для продвинутых сценариев
Если вы подключаете скрипты в <head>, но не хотите блокировать отрисовку - используйте атрибуты.
async- скрипт загружается асинхронно, не блокирует парсинг. Как только скачался - сразу выполняется. Подходит для скриптов, которые не зависят от других: аналитика, реклама, чат-боты.defer- скрипт загружается асинхронно, но выполняется после полной загрузки HTML, до событияDOMContentLoaded. Подходит для скриптов, которые работают с DOM, но не должны мешать отрисовке.
Пример:
<head>
<script src="analytics.js" async></script>
<script src="app.js" defer></script>
</head>
Важно: defer сохраняет порядок выполнения. Если у вас два скрипта с defer, они выполнятся в том порядке, в котором написаны в HTML. async - не гарантирует порядок.
Что делать с библиотеками вроде jQuery или React?
Если вы используете внешние библиотеки - их тоже нужно подключать правильно.
- jQuery - если он нужен для инициализации компонентов, подключайте его перед вашим собственным скриптом, но всё равно перед
</body>. Потому что ваш код зависит от него. - React, Vue, Angular - эти фреймворки требуют специальной сборки. Они не подключаются через обычный
<script>. Используйте Webpack, Vite или другие инструменты. Вручную подключать их в HTML - плохая практика.
Если вы используете CDN для React (например, react.development.js), то подключайте его с defer, а ваш основной скрипт - после него, тоже с defer.
Что не делать: распространённые ошибки
Вот что ломает производительность, даже если код идеальный:
- Подключать несколько скриптов подряд без
deferилиasync- каждый блокирует следующий. Браузер ждёт, пока первый закончится, потом второй, потом третий. Это как очередь в кассу: если один человек оплачивает 10 товаров - все позади ждут. - Писать JS внутри HTML -
<script>alert('Привет');</script>. Это мешает кэшированию, усложняет поддержку и замедляет загрузку. Всегда выносите в отдельный файл. - Подключать скрипты в
<head>без атрибутов - вы сознательно делаете сайт медленнее. - Загружать скрипты с медленных CDN - если вы используете
https://cdn.example.com/script.js, а сервер в США, а пользователь в Казани - время загрузки может быть 2-3 секунды. Лучше использовать локальные копии или CDN с ближайшими узлами (например, Cloudflare).
Как проверить, правильно ли вы подключили скрипты
Откройте Chrome DevTools (F12), перейдите на вкладку Network. Перезагрузите страницу. Посмотрите на столбец Waterfall. Если скрипты появляются в начале списка и блокируют отрисовку - вы сделали ошибку.
Также используйте Lighthouse (вкладка Audits). Он покажет вам предупреждение: “Remove render-blocking resources”. Это значит - ваши скрипты мешают отрисовке. Инструмент даже подскажет, какие именно файлы нужно перенести или добавить defer.
Хороший результат: Lighthouse показывает Speed Index ниже 2000. Это значит, пользователь видит контент за 2 секунды. Если выше - нужно пересмотреть место подключения скриптов.
Когда можно подключать скрипты в <head> без последствий
Есть случаи, когда это безопасно:
- Скрипт критичен для отрисовки: например, он меняет цвет фона или загружает шрифт через
FontFaceдо отображения текста. - Скрипт очень маленький (меньше 5 КБ) и не зависит от DOM.
- Вы используете
preloadилиprefetchдля ускорения загрузки. - Скрипт загружает важные данные для первого экрана (например, данные пользователя из API) и вы используете
async+deferвместе с состоянием загрузки.
Но даже в этих случаях лучше использовать defer, если скрипт работает с DOM. Это надёжнее.
Итог: как подключать скрипты правильно
Вот чек-лист, который можно распечатать и держать на рабочем столе:
- Все не критичные скрипты - перед закрывающим тегом
</body>. - Скрипты, которые зависят от DOM - с атрибутом
defer. - Скрипты, которые не зависят от других (аналитика, реклама) - с
async. - Никогда не пишите JS прямо в HTML - выносите в отдельные файлы.
- Проверяйте результат через Lighthouse и Network panel.
- Используйте локальные копии библиотек, если CDN медленный в вашем регионе.
Правильное подключение скриптов - это не про «так делают в примерах». Это про то, чтобы пользователь не ушёл, потому что сайт не открылся. В 2025 году, когда среднее время ожидания сайта - 1,8 секунды, каждая сотая секунды на счету. Не позволяйте скриптам быть причиной потери трафика.