В этой главе мы займемся размещением сценариев в HTML-документе, чтобы иметь возможность использовать их для оперативной модификации HTML-документа. Для вставки JavaScript-кoдa в НТМL-страницу обычно используют элемент <script>.

Чтобы ваша первая пpoгpaммa (или сценарий) JavaScript запустилась, ее нужно внедрить в НТМL-документ.
Сценарии внедряются в HTML-документ различными стандартными способами:

  • поместить код непосредственно в атрибут события HTML-элемента;
  • поместить код между открывающим и закрывающим тегами <script>;
  • поместить все ваши скрипты во внешний файл (с расширением .js), а затем связать его с документом HTML.

Самый простой способ внедрения JavaScript в HTML-документ – использование тега <script>. Теги <script> часто помещают в элемент <head>, и ранее этот способ считался чуть ли не обязательным. Однако в наши дни теги <script> используются как в элементе <head>, так и в теле веб-страниц.

Таким образом, на одной веб-странице могут располагаться сразу несколько сценариев. В какой последовательности браузер будет выполнять эти сценарии? Как правило, выполнение сценариев браузерами происходит по мере их загрузки. Браузер читает HTML-документ сверху вниз и, когда он встречает тег <script>, рассматривает текст программы как сценарий и выполняет его. Остальной контент страницы не загружается и не отображается, пока не будет выполнен весь код в элементе <script>.

Выполнить код »

Обратите внимание: мы указали атрибут language тега <script>, указывающий язык программирования, на котором написан сценарий. Значение атрибута language по умолчанию – JavaScript, поэтому, если вы используете скрипты на языке JavaScript, то вы можете не указывать атрибут language.

Вышеприведенный сценарий был выполнен при открытии страницы и вывел строку: «Привет, мир!». Однако не всегда нужно, чтобы выполнение сценария начиналось сразу при открытии страницы. Чаще всего требуется, чтобы программа запускалась при определенном событии, например при нажатии какой-то кнопки.

В следующем примере функция JavaScript помещается в раздел <head> HTML-документа. Вот пример HTML-элемента <button> с атрибутом события, обеспечивающим реакцию на щелчки мышью. При нажатии кнопки генерируется событие onclick.

Выполнить код »

Если 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>.

Вы уже знаете, что браузер читает 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>
    
    Вариант 2.
    
    <head>
    <script defer src="example.js"></script>
    </head>
    
    Вариант 3.
    
    <head>
    <script async src="example.js"></script>
    </head>
    
    Показать решение

    Решение:

    Атрибут defer откладывает выполнение скрипта до тех пор, пока вся HTML-страница не будет загружена полностью. Таким образом, во втором случае сценарий будет выполнен последним.

Комментарии

пожелания к комментариям…
  • Приветствуются комментарии, соответствующие теме урока: вопросы, ответы, предложения.
  • Одну строчку кода оборачивайте в тег <code>, несколько строчек кода — в теги <pre><code>...ваш код...</code></pre>.
  • Допускаются ссылки на онлайн-песочницы (codepen, plnkr, JSBin и др.).