Как браузер реагирует на внешний скрипт с атрибутом src и останавливает ли он рендеринг
Что проверяют
Различаете ли вы остановку парсинга HTML и остановку отрисовки и знаете ли точное поведение async и defer. Следом обычно спрашивают, в каком порядке выполнятся несколько таких скриптов и как ведут себя модули.
Как отвечать
Обычный <script src="..."> без атрибутов блокирует парсер. Браузер останавливает разбор HTML, скачивает файл, выполняет его и только потом продолжает: скрипт может менять документ, например через document.write. Отрисовку он блокирует косвенно. Всё, что выше тега, показать можно, ниже ещё ничего не разобрано, поэтому скрипт в <head> задерживает первую отрисовку всей страницы.
Две детали отличают сильный ответ:
- preload scanner: пока основной парсер стоит, вспомогательный сканер смотрит HTML дальше и заранее запрашивает картинки, стили и скрипты. Стоит разбор, а не сеть;
- CSS перед скриптом: скрипт не выполнится, пока не загружены стили, подключённые выше, ведь он может читать вычисленные стили. Медленный CSS задерживает и скрипт, и парсинг.
Атрибуты меняют поведение:
defer: загрузка параллельно с парсингом, выполнение после разбора документа, передDOMContentLoaded, строго в порядке следования в HTML;async: загрузка параллельно, выполнение сразу по готовности, парсер на это время встаёт. Порядок между скриптами не гарантирован;type="module": по умолчанию ведёт себя какdefer,asyncдля модулей тоже работает;- динамический скрипт через
document.createElementасинхронный по умолчанию.
У инлайнового скрипта без src атрибут defer игнорируется.
Где спотыкаются
Говорят, что defer выполняется после отрисовки страницы или по событию load. На деле он срабатывает сразу после разбора HTML и до DOMContentLoaded, картинки в этот момент могут ещё грузиться.
Вешают async на зависимые скрипты, например библиотеку и её плагин. Плагин иногда приходит первым, и ошибка появляется через раз.
Считают async бесплатным. Скрипт загружается параллельно, но на время выполнения парсер всё равно встаёт, и тяжёлая аналитика, пришедшая из кеша раньше разметки, задерживает первую отрисовку.