Ответ
<script> — блокирует парсинг HTML до загрузки и выполнения скрипта. Исполняется немедленно при встрече в документе.
<script async> — загружается асинхронно параллельно с парсингом HTML. Как только загрузился — сразу выполняется, при этом парсинг приостанавливается. Порядок выполнения не гарантирован.
<script defer> — загружается асинхронно, но выполняется только после полного парсинга HTML, перед событием DOMContentLoaded. Сохраняет порядок подключения скриптов.
Пример:
<script src="1.js"></script> <!-- блокирует -->
<script async src="2.js"></script> <!-- может выполниться раньше 3.js -->
<script defer src="3.js"></script> <!-- выполнится после DOM -->
Оптимально:
deferдля скриптов, зависящих от DOMasyncдля независимых скриптов (аналитика)- обычный
<script>в конце body, если важна совместимость
Ответ 18+ 🔞
А, вот эта тема про скрипты, да? Ну, слушай, это ж классика, как та самая история про Герасима и Муму, только в мире веба. Сейчас разжуем.
Представь себе, браузер — это такой Герасим, здоровый мужик, который строит дом (это наш HTML). И тут ему подсовывают скрипт.
<script> — это как приказ барыни: «Герасим! Немедленно брось всё, иди на речку и принеси воды!». Он всё бросает, идёт, тащит воду, возвращается и только потом продолжает кладку. Парсинг HTML встаёт нахуй, пока скрипт качается и выполняется. Полный пиздец для скорости.
<script async> — это уже хитрее. «Герасим, сходи за водой, но можешь параллельно с кирпичами таскать». Он пошёл, но как только вернулся с водой (скрипт загрузился) — БАМ! — сразу выливает её куда надо, снова прерывая работу. Главная проблема — порядок ебёт. Если ты послал его за водой, а потом сразу за хлебом (async 2.js), кто первый вернётся — тот и выполнится. Может хлеб раньше воды принести, ёпта.
<script defer> — это идеальный работник. «Герасим, сходи за водой, но принеси её только тогда, когда весь фундамент и стены будут готовы». Он спокойно загружает скрипт фоном, не мешая стройке, а выполняет его в самом конце, перед тем, как в дом можно заселяться (событие DOMContentLoaded). И порядок строго соблюдает: как отправил — вода, хлеб, соль — так и принесёт.
Пример, чтобы вообще мозг не взорвался:
<script src="1.js"></script> <!-- Стоп, землекоп! Ждём! -->
<script async src="2.js"></script> <!-- Качаюсь параллельно, но как скачаюсь — ёбну выполнюсь, может, раньше 3.js -->
<script defer src="3.js"></script> <!-- Качаюсь тихо, выполнюсь аккурат после всей разметки, и именно после 1.js и 2.js -->
Так как же не обосраться с выбором?
defer— твой друг, если скрипту нужно, чтобы DOM уже был готов. Почти всегда это то, что надо. Ставь в<head>и спи спокойно.async— для всякой независимой аналитики, счётчиков, которые как та собака Муму — им похуй на DOM, пусть живут своей жизнью. Выполнятся когда захотят.- Обычный
<script>в конце</body>— это как старый дедовский способ. Дом построил, а потом уже воду принёс. Работает везде, но современные методы (defer) обычно лучше.
Вот и вся философия. Главное — не делай как тот Герасим, который всё ломал направо и налево. Думай, что твоим скриптам нужно, и выбирай атрибут с умом, а не как попало.