С одной стороны, браузеру всё равно, когда мы подключили скрипт: он в любом случае его загрузит и будет с ним работать. С другой — от этого может зависеть скорость загрузки страницы. Рассказываем, какие бывают варианты и что будет в каждом из них.
Как подключить скрипт к странице
Допустим, у нас есть готовый скрипт, который подсвечивает манипуляцию и пропаганду на сайте. Мы сохранили код в файле script.js и хотим подключить его к своей странице. Для этого нам нужно добавить скрипт в раздел <head>
или <body>
с помощью команды:
<script src="script.js"></script>
Например, вот как это сделать в разделе <head>
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Заголовок</title>
<!-- добавляем скрипт в раздел head -->
<script src="script.js"></script>
</head>
<body>
</body>
</html>
А вот — в разделе <body>, где находится основное содержимое страницы:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Заголовок</title>
</head>
<body>
<!-- добавляем скрипт в раздел body -->
<script src="script.js"></script>
<!-- дальше какой-то HTML-код -->
</body>
</html>
В обоих случаях браузер загрузит нужный нам скрипт, но скорость загрузки страницы при этом может быть разной.
Как скрипт влияет на скорость загрузки
Когда браузер получает HTML-файл от сервера, он начинает обрабатывать его последовательно, шаг за шагом выполняя команды, которые там написаны. Если на странице сначала идёт заголовок, потом текст и картинка, то браузер и будет рисовать всё на странице именно в такой последовательности.
Тег подключения скрипта <script> — такой же тег для браузера, как тег заголовка <h1> или тег абзаца <p>. Это значит, что, как только браузер дойдёт до тега <script>, он остановит формирование внутреннего визуального каркаса страницы до тех пор, пока не загрузится скрипт. Если в нём есть самозапускающиеся функции — они начнут свою работу, а браузер всё это время будет ждать и не будет переходить к следующему тегу.
Получается, что браузер не сможет собрать финальную картинку для показа, пока не отработает все скрипты, которые идут до этого. Если мы подключим скрипт в самом начале страницы или в разделе <head>, то браузер сначала займётся ими, а потом только всем остальным. Если скриптов много или они большие, страница будет грузиться долго и пользователь будет это время просто ждать.
Как лучше сделать
Сейчас при вёрстке страницы принято подключать все скрипты в самом конце кода, перед тем, как закроется тег </body>:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Заголовок</title>
</head>
<body>
<!-- основной код страницы -->
<!-- добавляем скрипт в самом конце -->
<script src="script.js"></script>
</body>
</html>
Логика такая:
- Браузер получает HTML-код страницы и начинает его обрабатывать тег за тегом.
- Как только визуальные теги закончились — браузер выводит страницу на экран и пользователь уже видит готовый сайт.
- После этого браузер переходит к загрузке скрипта и, если нужно, — выполняет функции, которые там прописаны.
С таким подходом мы не тратим время на полную загрузку всех ресурсов, а сразу показываем читателю нужный ему материал, а в это время начинают грузиться и работать скрипты. Внешне это выглядит так, что сайт начал открываться быстрее, а работать — точно так же.
Лайфхак: асинхронная загрузка
Есть две внутренних атрибута, которые могут регулировать порядок загрузки скриптов на странице, — defer и async.
Defer. Если нам нужно, чтобы скрипт загружался фоном, параллельно со страницей, при объявлении скрипта можно добавить атрибут defer
:
<script src="script.js" defer></script>
В этом случае скрипт будет загружаться параллельно с основной страницей, но не будет выполняться до тех пор, пока она не загрузится полностью. Мы такое уже делали, когда писали свой таймер для спорта. При этом отложенные так скрипты будут выполняться в той же последовательности, как они прописаны в коде:
<!-- сначала выполнится этот скрипт -->
<script src="script_1.js" defer></script>
<!-- потом — этот -->
<script src="script_2.js" defer></script>
<!-- сначала выполнится этот скрипт -->
<script src="script_1.js" defer></script>
<!-- а затем — вот этот -->
<script src="script_3.js"></script>
Async. Этот атрибут даёт скрипту независимость: он будет загружаться фоном, параллельно со страницей, как и с defer
, и выполнится после своей загрузки. Это значит, что скрипт не ждёт, пока загрузится всё остальное, а просто выполняется по готовности:
<!-- скрипт загрузится и выполнится независимо от состояния страницы -->
<script src="script.js" async></script>
При таком подключении скрипт может сработать в любой момент — всё зависит только от скорости его загрузки. Иногда это может привести к тому, что сайт будет работать не так, как нужно: скрипт может попытаться обратиться к элементам на странице, которые ещё не загрузились. С другой стороны, таким способом на сайт часто добавляют счётчики посещаемости: неважно, когда он сработает, главное, чтобы просто сработал.
Если таким способом подключить несколько скриптов, то они тоже выполнятся в случайном порядке, что за чем успеет загрузиться, а не в той последовательности, которая написана в коде:
<!-- этот скрипт может загрузиться и сработать первым -->
<script src="script_1.js" async></script>
<!-- или, может, первым будет вот этот -->
<script src="script_2.js" async></script>
<!-- а может — этот -->
<script src="script_1.js" async></script>
<!-- но этот точно загрузится после всей страницы -->
<script src="script_2.js"></script>
Что дальше
В следующий раз мы соберём тестовую страницу с объёмными скриптами и посмотрим, как меняется время загрузки в зависимости от того, где и как мы подключили скрипт — в начале кода или в конце.