Почему лучше подключать скрипты в начале с defer или в конце без defer
Что проверяют
Понимаете ли вы, как загрузка скриптов вмешивается в разбор HTML, и отличаете ли defer от async. Правильный ответ звучит не как «так принято», а как объяснение, чем два способа различаются на медленной сети.
Как отвечать
Обычный <script src> в <head> блокирует парсер: браузер бросает построение DOM, качает файл, исполняет его и только потом продолжает разбор. Отсюда два обходных пути.
deferв<head>: файл скачивается параллельно с разбором документа, исполняется после того, как DOM построен, до событияDOMContentLoaded, строго в порядке следования тегов.- Скрипт в конце
<body>: парсер доходит до него последним, разметка к этому моменту уже отрисована, поэтому исполнение ничего не задерживает.
Результат похож, различается момент, когда браузер узнаёт про файл. Предзагрузочный сканер ищет src в уже полученных байтах, и если документ длинный или приезжает частями, ссылка из конца <body> найдётся позже, чем из <head>. То есть defer раньше начинает скачивание при том же порядке исполнения, и это главный довод в его пользу.
<script src="/app.js" defer></script>Стоит добавить про async: такой скрипт исполняется сразу по готовности файла, порядок между скриптами не гарантирован, и в момент исполнения парсер всё равно встанет. Режим для независимых вещей вроде счётчиков. У модулей (type="module") поведение defer включено по умолчанию.
Где спотыкаются
Считают defer и async синонимами «не блокирует». Порядок гарантирует только defer, поэтому библиотека и зависящий от неё код, подключённые через async, ломаются через раз, и воспроизводится это лишь на холодном кэше.
Вешают defer на встроенный скрипт без src. Атрибут в этом случае игнорируется, код выполняется на месте, а автор уверен, что отложил его.
Думают, что defer откладывает загрузку. Откладывается только исполнение, запрос уходит сразу и занимает канал наравне с картинками и стилями. Скрипт, не нужный на первом экране, грузят по событию или динамическим импортом, атрибут тут не поможет.