DOM Basics

Загрузка документа

Понять, когда HTML-код готов для JavaScript: разбор HTML, defer, type="module", DOMContentLoaded, и почему порядок загрузки имеет значение.

Начальный (Beginner)

Кратко

Браузер загружает 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, порядок не гарантирован.


Примеры

**Самый простой:**

javascript
// В HTML:
// <script type="module" src="app.js"></script>

// app.js — выполняется когда DOM готов:
const title = document.querySelector('h1');
console.log(title.textContent); // Работает!

type="module" гарантирует, что DOM готов к работе.

**Простой:**

javascript
// Сравнение подходов:

// ❌ Плохо: блокирует парсинг
// <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>

Четыре способа избежать блокировки парсинга.

**Реальный пример:**

javascript
// 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: области видимости, замыкания, классы и прототипы.

Материалы курса DOM Basics — PROlab Academy.