Почему лучше подключать скрипты в начале с defer или в конце без defer
Что проверяют
Понимаете ли вы, как разбор HTML связан с загрузкой и выполнением скриптов, и чем defer отличается от async. Следом обычно спрашивают, что происходит с событием DOMContentLoaded и куда вешать сторонние счётчики.
Как отвечать
Отправная точка: обычный <script src="..."> останавливает разбор документа. Парсер доходит до тега, ждёт загрузку файла, исполняет его и только потом строит DOM дальше. Именно поэтому скрипты когда-то уносили в конец <body>: к моменту исполнения разметка уже разобрана и страница успела отрисоваться.
Что делает defer: файл начинает грузиться сразу, параллельно с разбором HTML, а исполнение откладывается до конца разбора. Порядок между отложенными скриптами сохраняется, и все они отрабатывают до DOMContentLoaded. Получается лучшее из двух вариантов: раннее обнаружение ссылки и никакой блокировки парсера.
Сравните с соседними режимами:
async: тоже грузится параллельно, но исполняется сразу по готовности и может прервать разбор. Порядок не гарантирован, поэтому годится независимым скриптам вроде аналитики;type="module": откладывается по умолчанию,deferписать не нужно, аasyncдля модуля работает;- конец
bodyбезdefer: рабочий вариант, но хуже. Разметку выше браузер уже обработал, зато сам файл обнаруживается поздно. Отчасти спасает предзагрузочный сканер, но полагаться на него как на гарантию нельзя; - инлайновый скрипт:
deferиasyncдля него игнорируются, он всегда блокирующий.
Хорошо закончить оговоркой: defer не убирает стоимость парсинга и исполнения JavaScript в главном потоке, он лишь сдвигает её во времени. Если бандл тяжёлый, отзывчивость всё равно пострадает, и лечится это разбиением кода и загрузкой по требованию, а не одним атрибутом.
Где спотыкаются
Ставят defer на инлайновый скрипт и ждут отложенного запуска. Атрибут работает только вместе с src.
Меняют defer на async у скриптов с зависимостями. Порядок ломается, и плагин стартует раньше своей библиотеки.
Считают вынос в конец body полным эквивалентом defer. Разница в моменте обнаружения файла: defer в <head> даёт браузеру начать загрузку на первых килобайтах ответа.