Способы встраивания JavaScript кода в HTML документы

Раздел: Основы JavaScript -> Подключение скриптов в HTML

Подключение JavaScript скриптов в HTML

Основной и наиболее распространённый способ подключения внешнего JavaScript файла к HTML документу использует тег <script> с атрибутом src. Этот способ позволяет отделить код от разметки, улучшая читаемость и поддержку проекта.

<!DOCTYPE html>
<html>
  <head>
    <script src="scripts/main.js"></script>
  </head>
  <body>
    <!-- содержимое страницы -->
  </body>
</html>

Js script (подключение javascript скрипта)

Пояснения: браузер при встрече тега <script> с src останавливает парсинг HTML, загружает и выполняет скрипт, после чего продолжает построение DOM. Это может замедлить загрузку страницы, если скрипт расположен в <head>. Рекомендуется размещать тег перед закрывающим </body> или использовать атрибуты defer/async.

Типичные ошибки:

  • Неправильный путь к файлу (отсутствие файла, опечатка в имени). Решение: проверять консоль браузера (404 ошибка).
  • Скрипт пытается обратиться к элементам DOM, которые ещё не загружены (если скрипт в head). Решение: перенести скрипт в конец body или использовать defer.

Вопрос: Как добавить JavaScript код напрямую в HTML без внешнего файла?

Для встраивания кода используется тег <script> без атрибута src. Код пишется между открывающим и закрывающим тегами.

<script>
  console.log('Скрипт выполнен');
  document.querySelector('h1').style.color = 'blue';
</script>

Цель: быстрое прототипирование, маленькие проекты, когда нет необходимости в отдельных файлах.

Проблема:

Код нельзя повторно использовать на других страницах, сложно поддерживать. Если скрипт велик, страница становится громоздкой.

Вопрос: Как избежать блокировки загрузки страницы при подключении скрипта?

Размещение тега <script> перед закрывающим </body> гарантирует, что весь HTML будет уже распарсен, и скрипт не помешает рендерингу.

<!DOCTYPE html>
<html>
  <body>
    <h1>Заголовок</h1>
    <p>Текст параграфа</p>
    <script src="scripts/analytics.js"></script>
  </body>
</html>

Цель: обеспечить визуальное отображение контента до выполнения скрипта. Подходит для большинства случаев, когда скрипт не нужен для начального рендеринга.

Особенность:

Скрипт загружается и выполняется после того, как пользователь уже видит страницу, что может быть недостатком для скриптов, критичных для работы интерфейса (например, настройка A/B тестов).

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

Атрибут async указывает браузеру загружать скрипт параллельно с парсингом HTML и выполнить его сразу после загрузки, не дожидаясь завершения парсинга.

<head>
  <script src="scripts/widget.js" async></script>
</head>

Цель: независимые скрипты (например, счётчики, виджеты), порядок выполнения которых не важен. Скрипт может выполниться до полной загрузки DOM.

Ошибка:

Если скрипт обращается к элементам DOM, которые ещё не созданы, возникает ошибка. async не гарантирует наличие DOM. Используйте defer если нужен доступ к DOM.

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

Атрибут defer загружает скрипт параллельно с парсингом, но откладывает выполнение до момента, когда DOM будет полностью построен (событие DOMContentLoaded). Скрипты с defer выполняются в порядке их появления в HTML.

<head>
  <script src="scripts/app.js" defer></script>
  <script src="scripts/utils.js" defer></script>
</head>

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

Проблема:

В старых браузерах (IE9 и ниже) атрибут defer может работать некорректно. Для совместимости следует размещать скрипты в конце body.

Вопрос: Как подключить скрипт динамически, например, по действию пользователя?

Создать элемент <script> через JavaScript и добавить его в документ. Это позволяет загружать скрипты по требованию, экономя трафик.

const script = document.createElement('script');
script.src = 'scripts/chat.js';
script.onload = () => console.log('Скрипт загружен');
document.body.appendChild(script);

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

Ошибка:

Если скрипт добавить после полной загрузки, он может сломать уже работающий код. Следует предусмотреть проверки или использовать window.onload.

Вопрос: Как использовать современные модули JavaScript (ES6) в браузере?

Указать атрибут type="module" в теге <script>. Модули загружаются как defer по умолчанию, поддерживают import/export.

<script type="module" src="scripts/main.mjs"></script>
<script type="module">
  import { greeting } from './utils.js';
  console.log(greeting);
</script>

Цель: написание поддерживаемого кода с модульной структурой, избегание глобальных переменных.

Проблема:

Модули требуют сервера (не работают при открытии файла через file:// из-за CORS). Также старые браузеры не поддерживают type="module".

Расширенные примеры подключения JavaScript

В этом разделе представлены более сложные сценарии, включая комбинации атрибутов, обработку ошибок и работу с модулями.

Пример 1: Порядок выполнения скриптов с defer и async

Пример
<!DOCTYPE html>
<html>
<head>
  <script src="first.js" defer></script>
  <script src="second.js" async></script>
  <script src="third.js" defer></script>
</head>
<body>
  <h1>Тест</h1>
  <script>
    console.log('Inline скрипт');
  </script>
</body>
</html>

Результат выполнения:

Inline скрипт (сразу)
first.js (после загрузки DOM, первым среди defer)
third.js (вторым среди defer)
second.js (выполнится когда загрузится, возможно раньше или позже first.js)

Пояснение: async не ждёт порядок, а defer сохраняет порядок. Inline скрипт выполняется немедленно.

Пример 2: Динамическая загрузка с Promise и обработкой ошибок

Пример
function loadScript(src) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = src;
    script.onload = () => resolve(src);
    script.onerror = () => reject(new Error(`Не удалось загрузить ${src}`));
    document.head.appendChild(script);
  });
}

loadScript('analytics.js')
  .then(() => console.log('Скрипт analytics.js загружен'))
  .catch(err => console.error(err.message));

Результат: В консоли сообщение об успехе или ошибке.

Пояснение: Позволяет дождаться загрузки скрипта перед использованием его функций. Обработка onerror помогает отловить проблему сети.

Пример 3: Модуль с экспортом и импортом нескольких значений

Пример
// utils.js
export const PI = 3.14159;
export function double(n) {
  return n * 2;
}

// index.html
<script type="module">
  import { PI, double } from './utils.js';
  console.log(PI); // 3.14159
  console.log(double(5)); // 10
</script>

Результат: В консоли будут числа.

Пояснение: Работает только через HTTP сервер. Имена импортируемых переменных должны совпадать с экспортируемыми или использовать import * as utils.

Пример 4: Использование атрибута integrity для проверки целостности скрипта

Пример
<script
  src="https://cdn.example.com/library.js"
  integrity="sha384-Li9vy3DqF8tnTXuia13u5F6MXn47WfxQ5C9B8p7T/1FqYQ6sVfB3l9W8P9K3FXL"
  crossorigin="anonymous"
></script>

Пояснение: Хеш integrity гарантирует, что скрипт не был подменён. Браузер вычисляет хеш загруженного файла и сравнивает. Атрибут crossorigin обязателен для CDN.

Пример 5: Загрузка скрипта с установкой атрибута charset

Пример
<script src="scripts/data.js" charset="UTF-8"></script>

Пояснение: Если файл скрипта содержит не-ASCII символы (например, комментарии на русском), можно явно указать кодировку. По умолчанию браузер использует кодировку страницы.

Пример 6: Отложенная загрузка скрипта с использованием IntersectionObserver

Пример
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const script = document.createElement('script');
      script.src = 'comments.js';
      document.body.appendChild(script);
      observer.unobserve(entry.target);
    }
  });
});
observer.observe(document.getElementById('comments-section'));

Пояснение: Скрипт загрузится только когда секция комментариев появится в зоне видимости. Экономит трафик и ускоряет начальную загрузку.

Подключение JavaScript скрипта - comments

En
Js script (javascript)