Что происходит при встрече с тегами link, img, script при формировании DOM-дерева

Ответ

При парсинге HTML браузер встречает эти теги и обрабатывает их особым образом:

  • <link> (с атрибутом rel="stylesheet") - блокирует рендеринг до загрузки CSS-файла, но не блокирует парсинг HTML. DOM-элемент создаётся сразу.

  • <img> - не блокирует парсинг и рендеринг. Изображение загружается асинхронно, DOM-элемент создаётся сразу, но отрисовка может произойти позже.

  • <script> - по умолчанию блокирует парсинг HTML до загрузки и выполнения скрипта. DOM-элемент создаётся после выполнения.

Пример с async/defer:

<script src="script.js" defer></script> <!-- выполнится после парсинга -->
<script src="script.js" async></script> <!-- выполнится при готовности -->

Ответ 18+ 🔞

Слушай, а вот этот ваш HTML, он же, блядь, не просто так читается, как книжка! Браузер его разбирает, как заправский хирург, и натыкается на разные штуки. И ведёт себя с ними по-разному, вот в чём прикол!

Вот смотри, например, тег <link> с этим самым rel="stylesheet". Ну, тот, что стили тянет. Так вот, он, сука, рендеринг страницы притормозит, пока CSS не подгрузится — браузеру надо знать, как всё рисовать. Но сам парсинг HTML, то есть чтение кода дальше, он не блокирует, ёпта! DOM-элемент для этой ссылки создаст сразу, а стили потом подтянет. Хитрая жопа!

Дальше, <img>. Картинка. Вот это вообще асинхронный чемпион, блядь! Она ни парсинг, ни рендеринг не блокирует вообще. DOM-элемент — раз! — создали. А сама картинка будет грузиться где-то на фоне, как придётся. Нарисуется она потом, когда доползёт. Можно хоть десять мегабайтовых фото вставить — страница текст покажет, а фото позже догрузятся. Удобно, чё.

А теперь, блядь, король всех тормозов — классический <script>! Он, сука, по умолчанию и парсинг HTML, и всё остальное заблокирует, пока сам не скачается и не выполнится. Потому что скрипт может всё переписать нахуй! DOM-элемент для этого скрипта создастся только после его выполнения. Представляешь? Вся страница встала колом из-за одного скрипта-недоростка!

Но, слава богу, есть две волшебные пилюли от этой головной боли: async и defer.

Вот смотри, пример кода, тут всё понятно:

<script src="script.js" defer></script> <!-- выполнится после парсинга, но до DOMContentLoaded -->
<script src="script.js" async></script> <!-- выполнится как только скачается, не дожидаясь никого -->

Короче, defer — это вежливый скрипт: "Я подожду, пока весь HTML прочитают, а потом запущусь". А async — это скрипт-непоседа: "Я запущусь, как только я сам буду готов, а там хоть трава не расти, парсинг не парсинг!"

Вот так вот, вся разница, блядь. Ёпта, а ведь кто-то это всё придумал.