JavaScript на странице: способы встраивания через тег script

Раздел: Веб-разработка -> HTML/CSS/JS связь

Основные методы подключения тега script

Веб-разработка предполагает тесную связь HTML, CSS и JavaScript. Тег <script> является основным инструментом для внедрения JS-кода в HTML-документ. Существует несколько подходов, и наиболее предпочтительным в современных проектах считается использование атрибута defer для внешних скриптов.

Вопрос: Как подключить внешний JavaScript, чтобы не блокировать отображение страницы и сохранить порядок выполнения?

Ответ: атрибут defer. Пример:

<script src='app.js' defer></script>

Link href js html (подключение javascript файлов в html)

Пояснение: атрибут defer даёт браузеру команду загружать скрипт параллельно с парсингом HTML, но откладывает его выполнение до момента, когда весь HTML будет полностью разобран. Скрипты с defer выполняются в порядке их появления в документе, непосредственно перед событием DOMContentLoaded. Это обеспечивает доступ к полной DOM-структуре без задержек рендеринга.

Типичные проблемы и их решения:

  • Проблема: defer не работает для встроенных (inline) скриптов. Решение: для inline-кода используется размещение в конце <body> или атрибут type='module'.
  • Проблема: Старые браузеры (IE9 и ниже) не поддерживают defer. Решение: для совместимости добавлять скрипт в конце <body> или использовать полифиллы.
  • Проблема: Скрипт использует document.write. Решение: заменить document.write на современные методы манипуляции DOM, так как defer не предотвращает проблем, связанных с этим устаревшим методом.

Вариант: внутренний скрипт в конце <body>

Вопрос: Как выполнить скрипт после загрузки всех HTML-элементов без использования дополнительных атрибутов?

Ответ: разместить тег <script> непосредственно перед закрывающим тегом </body>. Пример:

<!DOCTYPE html>
<html>
<head>...</head>
<body>
  <!-- содержимое страницы -->
  <script>
    console.log('Страница загружена');
  </script>
</body>
</html>

Js теги (теги script в html)

Пояснение: браузер парсит HTML сверху вниз. Когда он встречает <script> (без атрибутов async или defer), он приостанавливает парсинг, загружает (если внешний) и выполняет скрипт. Размещая скрипт в самом конце, гарантируется, что все предыдущие элементы DOM уже доступны. Это простой и надёжный способ для небольших скриптов.

Типичные проблемы и их решения:

  • Проблема: Если скрипт внешний (src), загрузка файла может задержать отображение страницы, так как браузер ждёт завершения загрузки перед продолжением парсинга. Решение: использовать defer или async.
  • Проблема: Для больших inline-скриптов парсинг HTML задерживается, увеличивая время до первого рендеринга. Решение: вынести код во внешний файл с defer.

Вариант: внешний скрипт в <head> без атрибутов

Вопрос: Как подключить внешний файл, когда необходимо, чтобы скрипт выполнился до начала отображения содержимого?

Ответ: разместить <script src='script.js'></script> в <head>. Пример:

<head>
  <script src='analytics.js'></script>
</head>

Пояснение: такой способ блокирует парсинг и рендеринг HTML до полной загрузки и выполнения скрипта. Используется редко, в основном для скриптов, которые должны быть доступны с самого начала (например, для переопределения глобальных функций или для библиотек, необходимых для инициализации).

Типичные проблемы и их решения:

  • Проблема: Сильное замедление загрузки страницы, особенно при медленных сетях. Решение: переместить скрипт в конец <body> или добавить async/defer.
  • Проблема: Если скрипт обращается к элементам DOM, которые ещё не созданы, возникает ошибка. Решение: обернуть код в обработчик события DOMContentLoaded или использовать defer.

Вариант: атрибут async

Вопрос: Как загрузить внешний скрипт параллельно и выполнить его сразу после загрузки, не дожидаясь полного парсинга HTML?

Ответ: добавить атрибут async. Пример:

<script src='analytics.js' async></script>

Пояснение: браузер загружает скрипт асинхронно (не блокируя парсинг). Как только файл загружен, скрипт выполняется, даже если HTML ещё не полностью разобран. Порядок выполнения нескольких async-скриптов не гарантируется. Идеально для скриптов, которые не зависят от DOM и друг от друга (счётчики, реклама).

Типичные проблемы и их решения:

  • Проблема: Скрипт обращается к DOM-элементам, которые ещё не созданы. Решение: проверять существование элементов или использовать обработчик DOMContentLoaded.
  • Проблема: Если несколько async-скриптов зависят друг от друга, порядок выполнения может нарушиться. Решение: использовать defer или объединить скрипты в один.

Вариант: атрибут type='module'

Вопрос: Как подключить модульный JavaScript с автоматическим отложенным выполнением и поддержкой импорта/экспорта?

Ответ: указать type='module'. Пример:

<script type='module' src='main.mjs'></script>

Пояснение: скрипты с type='module' автоматически ведут себя как defer (выполняются после парсинга). Они работают в строгом режиме, поддерживают import и export. Модули могут быть встроенными или внешними. Для внешних модулей требуется соблюдение CORS.

Типичные проблемы и их решения:

  • Проблема: Модули не работают в старых браузерах. Решение: использовать атрибут nomodule для запасного варианта.
  • Проблема: Ошибка CORS при загрузке модуля с другого домена. Решение: настроить сервер для отправки корректных заголовков CORS.
  • Проблема: Встроенные модули (inline) не кэшируются браузером. Решение: для повторного использования выносить модуль во внешний файл.

Примеры расширенного использования тега script

Пример
// Создаём элемент script
var script = document.createElement('script');
script.src = 'lazy.js';
script.async = true;
document.head.appendChild(script);

Результат: скрипт lazy.js загружается и выполняется асинхронно. Этот метод позволяет загружать скрипты после каких-либо действий пользователя (например, после клика).

(в консоли браузера появится вывод из lazy.js, если он есть)
Пример
<script src='https://cdn.example.com/lib.js'
        integrity='sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC'
        crossorigin='anonymous'></script>

Пояснение: атрибут integrity содержит криптографический хеш (SHA-384) содержимого файла. Браузер вычисляет хеш загруженного файла и сравнивает с указанным. Если хеши не совпадают, скрипт не выполняется. Это защита от подмены файла при использовании CDN.

Скрипт выполнится только если содержимое совпадает с хешем. При несовпадении – ошибка в консоли.
Пример
<script type='module' src='modern.js'></script>
<script nomodule src='legacy.js'></script>

Пояснение: браузеры, поддерживающие модули, загрузят modern.js и проигнорируют скрипт с nomodule. Старые браузеры, не понимающие type='module', загрузят legacy.js. Это позволяет поддерживать старые версии без дублирования кода.

В современных браузерах выполнится modern.js, в старых – legacy.js.
Пример
<script defer src='first.js'></script>
<script defer src='second.js'></script>
<script defer src='third.js'></script>

Пояснение: все три скрипта загружаются параллельно, но выполняются строго в порядке появления: first.js, затем second.js, затем third.js – после полного парсинга HTML. Это важно, если второй скрипт зависит от первого.

В консоль выводятся сообщения из каждого файла в порядке first, second, third.
Пример
<script>
  document.write('<p>Этот текст будет вставлен</p>');
</script>

Пояснение: document.write может использоваться только во время парсинга. Если вызвать его после загрузки страницы (например, в async или defer скрипте), он перезапишет весь документ. Поэтому не рекомендуется использовать document.write в современных скриптах.

При выполнении после парсинга – страница очищается и отображается только вставленный текст.
Пример
<script src='https://api.example.com/widget.js' crossorigin='anonymous'></script>

Пояснение: при загрузке скрипта с другого домена браузер отправляет запрос с заголовком Origin. Атрибут crossorigin указывает, следует ли передавать учётные данные (cookies, сертификаты). Значение anonymous означает запрос без учётных данных. Необходим для модулей (type='module') и для получения ошибок выполнения (если сервер настроен на CORS).

Скрипт загрузится, если сервер разрешает CORS; иначе – ошибка.
Пример
<script type='module'>
  import { sayHello } from './hello.js';
  sayHello('Мир');
</script>

hello.js:

Пример
export function sayHello(name) {
  console.log(`Привет, ${name}!`);
}
В консоль выводится 'Привет, Мир!'
Пример
<script type='module' src='./utils/helpers.mjs'></script>

Пояснение: расширение .mjs или .js – не важно, главное, чтобы сервер возвращал правильный MIME-тип (text/javascript или application/javascript). Модули должны быть доступны по тому же протоколу (HTTP/HTTPS).

Теги script в HTML - comments

En
Js теги (javascript)