Подключение скриптов: script тег
Тег
<script>подключает JavaScript к HTML-странице: либо встроенный код, либо внешний файл; атрибутыdeferиasyncуправляют порядком загрузки и выполнения.
Зачем нужно
Неправильное подключение скриптов ведёт к блокировке рендеринга страницы, ошибкам «элемент не найден» и медленной загрузке. Понимание defer/async и типа модуля позволяет оптимально управлять порядком выполнения и производительностью.
Где используется
- Подключение JavaScript в любом HTML-документе
- Подключение библиотек (jQuery, analytics, tracking)
- Модульные приложения (
type="module") - Динамическая загрузка скриптов в runtime
Базовый синтаксис
<!-- Встроенный код (inline script) -->
<script>
console.log('Привет, мир!');
</script>
<!-- Внешний файл -->
<script src="./app.js"></script>
<!-- ES-модуль -->
<script type="module" src="./main.js"></script>
Обычный script (блокирующий)
Браузер останавливает парсинг HTML, загружает и выполняет скрипт, затем продолжает.
<head>
<!-- Плохо в <head> без defer/async: блокирует рендер -->
<script src="heavy.js"></script>
</head>
Исторический приём — ставить <script> перед </body>:
<body>
<div id="app"></div>
<!-- DOM уже построен к моменту выполнения -->
<script src="app.js"></script>
</body>
defer — отложенное выполнение
Скрипт загружается параллельно с HTML, выполняется после полного парсинга DOM, в порядке объявления:
<head>
<!-- Загружаются параллельно, выполняются по порядку после DOM -->
<script defer src="lib.js"></script>
<script defer src="app.js"></script>
<!-- app.js всегда запустится после lib.js -->
</head>
Эквивалентно обработчику DOMContentLoaded.
async — асинхронное выполнение
Скрипт загружается параллельно и выполняется сразу после загрузки, не ожидая DOM и других скриптов:
<head>
<!-- Выполнится как только загрузится — порядок не гарантирован -->
<script async src="analytics.js"></script>
<script async src="ads.js"></script>
</head>
Подходит для независимых скриптов (аналитика, реклама).
Сравнительная таблица
| Атрибут | Загрузка | Блокировка HTML | Порядок |
|---|---|---|---|
| (нет) | Синхронная | Да | Да |
defer |
Параллельная | Нет | Сохраняется |
async |
Параллельная | Нет | Не гарантирован |
type="module"
<script type="module" src="./main.js"></script>
- Автоматически
deferпо умолчанию - Строгий режим (
'use strict') - Изолированная область видимости
- Поддержка
import/export - Загружается один раз, даже при нескольких тегах с одним
src
Динамическое подключение скрипта
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Ошибка загрузки: ${src}`));
document.head.appendChild(script);
});
}
// Ленивая загрузка
button.addEventListener('click', async () => {
await loadScript('/libs/chart.js');
renderChart;
});
Частые ошибки
1. defer с inline-скриптами не работает
<!-- defer игнорируется для встроенного кода -->
<script defer>
document.querySelector('#app'); // может быть null — defer не применяется
</script>
2. type="module" блокирует доступ к глобальным переменным
<script type="module">
window.myVar = 42; // OK, но...
</script>
<script>
console.log(myVar); // может не найти, если другой скрипт выполнился раньше
</script>
3. Нарушение порядка зависимостей с async
<!-- app.js зависит от lib.js, но async не гарантирует порядок -->
<script async src="lib.js"></script>
<script async src="app.js"></script> <!-- может запуститься до lib.js! -->
<!-- Используй defer или bundler -->
Связанные темы
- Модули -- import и export
- События загрузки -- DOMContentLoaded, load
- DOM дерево
- _MOC DOM
- _MOC JavaScript