В этой главе мы займемся размещением сценариев в HTML-документе, чтобы иметь возможность использовать их для оперативной модификации HTML-документа. Для вставки JavaScript-кoдa в НТМL-страницу обычно используют элемент <script>
.
Первая программа
Чтобы ваша первая пpoгpaммa (или сценарий) JavaScript запустилась, ее нужно внедрить в НТМL-документ.
Сценарии внедряются в HTML-документ различными стандартными способами:
- поместить код непосредственно в атрибут события HTML-элемента;
- поместить код между открывающим и закрывающим тегами
<script>
; - поместить все ваши скрипты во внешний файл (с расширением .js), а затем связать его с документом HTML.
JavaScript в элементе script
Самый простой способ внедрения JavaScript в HTML-документ – использование тега <script>
. Теги <script>
часто помещают в элемент <head>
, и ранее этот способ считался чуть ли не обязательным. Однако в наши дни теги <script>
используются как в элементе <head>
, так и в теле веб-страниц.
Таким образом, на одной веб-странице могут располагаться сразу несколько сценариев. В какой последовательности браузер будет выполнять эти сценарии?
Как правило, выполнение сценариев браузерами происходит по мере их загрузки.
Браузер читает HTML-документ сверху вниз и, когда он встречает тег <script>
, рассматривает текст программы как сценарий и выполняет его. Остальной контент страницы не загружается и не отображается, пока не будет выполнен весь код в элементе <script>
.
Обратите внимание: мы указали атрибут language
тега <script>
, указывающий язык программирования, на котором написан сценарий. Значение атрибута language
по умолчанию – JavaScript, поэтому, если вы используете скрипты на языке JavaScript, то вы можете не указывать атрибут language
.
JavaScript в атрибутах событий HTML-элементов
Вышеприведенный сценарий был выполнен при открытии страницы и вывел строку: «Привет, мир!». Однако не всегда нужно, чтобы выполнение сценария начиналось сразу при открытии страницы. Чаще всего требуется, чтобы программа запускалась при определенном событии, например при нажатии какой-то кнопки.
В следующем примере функция JavaScript помещается в раздел <head>
HTML-документа. Вот пример HTML-элемента <button>
с атрибутом события, обеспечивающим реакцию на щелчки мышью. При нажатии кнопки генерируется событие onclick.
Внешний JavaScript
Если JavaScript-кода много – его выносят в отдельный файл, который, как правило, имеет расширение .js
.
Чтобы включить в HTML-документ JavaScript-кoд из внешнего файла, нужно использовать атрибут src
(source) тега <script>
. Его значением должен быть URL-aдpec файла, в котором содержится JS-код:
<script src="/scripts/script.js"></script>
В этом примере указан абсолютный путь к файлу с именем script.js, содержащему скрипт (из корня сайта). Сам файл должен содержать только JavaScript-кoд, который иначе располагался бы между тегами <script>
и </script>
.
По аналогии с элементом <img>
атрибуту src
элемента <script>
можно назначить полный URL-aдpec, не относящийся к домену текущей НТМL-страницы:
<script src=" http://www.somesite.com/script.js"></script>
На заметку: Подробнее о путях файлов читайте в разделе «Абсолютные и относительные ссылки».
Чтобы подключить несколько скриптов, используйте несколько тегов:
<script src="/scripts/script1.js"></script>
<script src="/scripts/script2.js"></script>
...
Примечание: Элемент <script>
с атрибутом src
не может содержать дополнительный JаvаSсriрt-код между тегами <script>
и </script>
, хотя внешний сценарий выполняется, встроенный код игнорируется.
Независимо от того, как JS-код включается в НТМL-документ, элементы <script>
интерпретируются браузером в том порядке, в котором они расположены в HTML-документе. Сначала интерпретируется код первого элемента <script>
, затем браузер приступает ко второму элементу <script>
и т. д.
Внешние скрипты практичны, когда один и тот же код используется во многих разных веб-страницах. Браузер скачает js-файл один раз и в дальнейшем будет брать его из своего кеша, благодаря чему один и тот же скрипт, содержащий, к примеру, библиотеку функций, может использоваться на разных страницах без полной перезагрузки с сервера. Кроме этого, благодаря внешним скриптам, упрощается сопровождение кода, поскольку вносить изменения или исправлять ошибки приходится только в одном месте.
Примечание: Во внешние файлы копируется только JavaScript-код без указания открывающего и закрывающего тегов <script>
и </script>
.
Расположение тегов <script>
Вы уже знаете, что браузер читает HTML-документ сверху вниз и, начинает отображать страницу, показывая часть документа до тега <script>
. Встретив тег <script>
, переключается в JavaScript-режим и выполняет сценарий. Закончив выполнение, возвращается обратно в HTML-режим и отображает оставшуюся часть документа.
Это наглядно демонстрирует следующий пример. Метод alert() выводит на экран модальное окно с сообщением и приостанавливает выполнение скрипта, пока пользователь не нажмёт «ОК»:
Если на странице используется много скриптов JavaScript, то могут возникнуть длительные задержки при загрузке, в течение которых пользователь видит пустое окно браузера. Поэтому считается хорошей практикой все ссылки нa javaScript-cцeнapии указывать после контента страницы перед закрывающим тегом <body>
:
<body>
<!-- Контент страницы -->
<script src="scriptl.js"></script>
<script src="script2.js"></script>
</body>
Такое расположение сценариев позволяет браузеру загружать страницу быстрее, так как сначала загрузится контент страницы, а потом будет загружаться код сценария.
Для пользователей это предпочтительнее, потому что страница полностью визуализируется в браузере до обработки JavaScript-кoдa.
Отложенные и асинхронные сценарии
Как отмечалось ранее, по умолчанию файлы JavaScript-кода прерывают синтаксический анализ (парсинг) HTML-документа до тех пор, пока скрипт не будет загружен и выполнен, тем самым увеличивая промежуток времени до первой отрисовки страницы.
Возьмём пример, в котором элемент <script>
расположен где-то в середине страницы:
<html>
<body>
какой-то текст...
<script src="script.js"></script>
Этот текст не будет показан, пока браузер не выполнит script.js.
</body>
</html>
В этом примере, пока пока браузер не загрузит и не выполнит script.js, он не покажет часть страницы под ним. Такое поведение браузера называется «синхронным» и может доставить проблемы, если мы загружаем несколько JavaScript-файлов на странице, так как это увеличивает время её отрисовки.
А что, если HTML-документ на самом деле не зависит от этих JS-файлов, а разработчик желает контролировать то, как внешние файлы загружаются и выполняются?
Кардинально решить проблему загрузки скриптов помогут атрибуты async
и defer
элемента <script>
.
Атрибут async
Async используется для того, чтобы указать браузеру, что скрипт может быть выполнен «асинхронно».
При обнаружении тега <script async src="...">
браузер не останавливает обработку HTML-документа для загрузки и выполнения скрипта, выполнение может произойти после того, как скрипт будет получен параллельно с разбором документа. Когда скрипт будет загружен – он выполнится.
Для сценариев с атрибутом async
не гарантируется выполнение скриптов в порядке их добавления, например:
<html>
<head>
</head>
<body>
<script async src="script1.js"></script>
<script async src="script2.js"></script>
<!-- контент -->
</body>
</html>
В примере второй скрипт может быть выполнен перед первым, поэтому важно, чтобы между этими сценариями не было зависимостей.
Примечание: Атрибут async
используется, если нужно разрешить браузеру продолжить загрузку страницы, не дожидаясь завершения загрузки и выполнения сценария.
Атрибут defer
Атрибут defer
откладывает выполнение скрипта до тех пор, пока вся HTML-страница не будет загружена полностью.
Как и при асинхронной загрузке скриптов — JS-файл может быть загружен, в то время как HTML-документ ещё грузится. Однако, даже если скрипт будет полностью загружен ещё до того, как браузер закончит обработку страницы, он не будет выполнен до тех пор, пока HTML-документ не обработается до конца.
<html>
<head>
<script defer src="script1.js"></script>
<script defer src="script2.js"></script>
</head>
<body>
<!-- контент -->
</body>
</html>
Несмотря на то, что в приведенном примере теги <script defer src="...">
включены в элемент <head>
HTML-документа, выполнение сценариев не начнется, пока браузер не дойдет до закрывающего тега </html>
.
Кроме того, в отличие от async
, относительный порядок выполнения скриптов с атрибутом defer
будет сохранён.
Применение атрибута defer
бывает полезным, когда в коде скрипта предусматривается работа с HTML-документом, и разработчик должен быть уверен, что страница полностью получена.
Примечание: Атрибуты async
и defer
поддерживаются только для внешних файлов сценариев, т.е. работают только при наличии атрибута src
.
Итоги
- JavaScript можно добавить в HTML-документ с помощью элемента
<script>
двумя способами:- Определить встроенный сценарий, который располагается непосредственно между парой тегов
<script>
и</script>
. - Подключить внешний файл с JavaScript-кодом через
<script src="путь"></script>
.
- Определить встроенный сценарий, который располагается непосредственно между парой тегов
- Если JavaScript-код используется в нескольких страницах, то его лучше подключать в качестве внешнего сценария. Это существенно облегчает сопровождение и редактирование кода, а также ускорит загрузку и обработку веб-страниц – внешний сценарий загружается браузером всего один раз (в дальнейшем он будет извлекаться из кэша браузера).
- Атрибут
defer
сигнализирует браузеру, что загрузку сценария можно начать немедленно, но его выполнение следует отложить до тех пор, пока весь HTML-документ будет загружен. - В тех случаях, когда файл скрипта содержит функции, взаимодействующие с загружаемым HTML-документом или существует зависимость от другого файла на странице необходимо, чтобы HTML-документ был полностью загружен, прежде чем скрипт будет выполнен. Как правило, такая ссылка нa javaScript-cцeнapий помещается в низ страницы перед закрывающим тегом <body>, чтобы убедиться, что для его работы весь документ был разобран. Однако, в ситуации, когда по каким-либо причинам JS-файл должен быть размещён в другом месте документа — атрибут
defer
может быть полезен. - Атрибут
defer
сохраняет относительную последовательность выполнения скриптов, аasync
– нет. - Скрипт с атрибутом
async
выполняется асинхронно с обработкой страницы, когда скрипт будет загружен – он выполнится, даже если HTML-документ ещё не полностью готов. - Для JS-файлов, которые не зависят от других файлов, атрибут
async
будет наиболее полезен. Поскольку нам не важно, когда скрипт будет исполнен, асинхронная загрузка — наиболее подходящий вариант.
Задачи
-
Всплывающее окно
Перед вами простой HTML-документ. Разместите в теле НТМL-страницы сценарий, выводящий всплывающее окно с надписью: "Привет, javascript!"
Решение:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Мой первый javascript</title> </head> <body> <p>Это обычный HTML документ</p> <script> alert("Привет, javascript!"); </script> </body> </html>
-
Подключение внешнего скрипта
Включите в НТМL-страницу сценарий из внешнего файла script.js, который расположен в той же директории, где располагается и сам HTML-документ.
Решение:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Мой первый javascript</title> </head> <body> <p>Это обычный HTML документ</p> <script src="script.js"></script> </body> </html>
-
Внешний скрипт с встроенным JаvаSсriрt кодом
Внешний файл script.js содержит сценарий, который выводит модальное окно с надписью: "Сработал внешний скрипт – script.js!". Какая надпись будет выведена в окне браузера?
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script src="script.js"> alert("Привет, javascript!"); </script> </body> </html>
Решение:
Элемент
<script>
с атрибутомsrc
не может содержать дополнительный JаvаSсriрt-код между тегами<script>
и</script>
, так как сработает только внешний сценарий, а встроенный код игнорируется. Таким образом будет выведена фраза: "Сработал внешний скрипт – script.js!".
-
Какой скрипт выполнится последним?
В примере ниже к HTML-документу подключен скрипт example.js. Скрипт относительно мал и загружается гораздо обыстрее, чем сам документ. В каком случае сценарий выполнится последним?
Вариант 1.<head> <script src="example.js"></script> </head>
<head> <script defer src="example.js"></script> </head>
<head> <script async src="example.js"></script> </head>
Решение:
Атрибут
defer
откладывает выполнение скрипта до тех пор, пока вся HTML-страница не будет загружена полностью. Таким образом, во втором случае сценарий будет выполнен последним.
Комментарии
<code>
, несколько строчек кода — в теги<pre><code>
...ваш код...</code></pre>
.