Кратко
Браузер загружает HTML сверху вниз. <script> блокирует парсинг. defer загружает скрипт параллельно и выполняет после HTML. type="module" загружает как модуль (defer по умолчанию). DOMContentLoaded — событие, когда DOM готов.
Подробно
Как браузер загружает страницу:
- Скачивает HTML (текст)
- Парсит сверху вниз
- Встречает <script> — ОСТАНАВЛИВАЕТ парсинг
- Скачивает и выполняет скрипт
- Продолжает парсинг
- Когда весь HTML распарсен → DOMContentLoaded
- Когда все ресурсы загружены → load
Проблема: <script src="app.js"></script> // Парсинг HTML остановился! Если app.js большой — пользователь ждёт.
Решения:
- defer (атрибут):
<script src="app.js" defer></script> - Скачивает скрипт параллельно с HTML - Выполняет ПОСЛЕ полного парсинга HTML - Порядок сохраняется (первый скрипт → первый)
- async:
<script src="app.js" async></script> - Скачивает параллельно - Выполняет КОГДА готов (порядок НЕ гарантирован)
- type="module":
<script type="module" src="app.js"></script> -.defer по умолчанию - Изолированная область видимости - Поддерживает import/export
- Скрипт в конце body:
<body> <!-- контент --> <script src="app.js"></script> </body>
События загрузки:
- DOMContentLoaded:
- Fired когда DOM распарсен (без ожидания CSS, картинок) - Скрипт с defer выполняется до этого события
- load:
- Fired когда ВСЁ загружено (CSS, картинки, шрифты)
Практические правила:
- Используйте type="module" — modern approach
- Или defer — для не-модульных скриптов
- НЕ используйте async без понимания порядка
- Не скрипт в head без defer/async — блокирует рендер
Ментальная модель
Загрузка страницы — как чтение книги. Читаете сверху вниз. Встретили скрипт (приписку) — остановились, прочитали приписку, продолжили. defer — приписка читается после всей книги. async — приписка читается когда будет hazır, порядок не гарантирован.
Примеры
**Самый простой:**
// В HTML:
// <script type="module" src="app.js"></script>
// app.js — выполняется когда DOM готов:
const title = document.querySelector('h1');
console.log(title.textContent); // Работает!type="module" гарантирует, что DOM готов к работе.
**Простой:**
// Сравнение подходов:
// ❌ Плохо: блокирует парсинг
// <script src="app.js"></script>
// ✅ Хорошо: defer
// <script src="app.js" defer></script>
// ✅ Хорошо: module
// <script type="module" src="app.js"></script>
// ✅ Хорошо: в конце body
// <body>
// <!-- контент -->
// <script src="app.js"></script>
// </body>Четыре способа избежать блокировки парсинга.
**Реальный пример:**
// DOMContentLoaded — когда DOM готов:
document.addEventListener('DOMContentLoaded', () => {
// DOM распарсен, можно безопасно искать элементы
const app = document.querySelector('#app');
console.log('DOM готов!', app);
});
// load — когда ВСЁ загружено:
window.addEventListener('load', () => {
// CSS, картинки, шрифты — всё загружено
console.log('Полная загрузка!');
});DOMContentLoaded — для работы с DOM. load — для ожидания всех ресурсов.
Частые ошибки
**Неправильно:** Думать, что DOMContentLoaded = load
**Почему:** DOMContentLoaded — DOM готов. load — ВСЁ загружено (CSS, картинки).
**Правильно:** DOMContentLoaded — раньше. load — позже.
**Неправильно:** Использовать defer и async одновременно
**Почему:** async игнорируется, если есть defer. Не используйте оба.
**Правильно:** Выберите один: defer ИЛИ async. Лучше — type="module".
**Неправильно:** Думать, что скрипт без атрибутов безопасен
**Почему:** <script src="app.js"></script> блокирует парсинг HTML.
**Правильно:** Всегда используйте defer, async или type="module".
**Неправильно:** Говорить «нужно всегда оборачивать в DOMContentLoaded»
**Почему:** type="module" и defer уже гарантируют, что DOM готов. DOMContentLoaded не нужен.
**Правильно:** Для module/defer — DOMContentLoaded не нужен. Для обычных скриптов — может понадобиться.
Важно запомнить
- <script> блокирует парсинг HTML
- defer — выполняет после парсинга (порядок сохраняется)
- type="module" — defer по умолчанию + модули
- DOMContentLoaded — DOM готов (не ждёт CSS/картинки)
- load — ВСЁ загружено
Связь
Назад: Вы умеете стилизовать элементы (D7) — теперь вы понимаете, когда безопасно запускать JavaScript.
Вперёд: Вы завершили DOM Basics (D1-D8)! Дальше — JS Intermediate: области видимости, замыкания, классы и прототипы.