Способы встраивания 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'));
Пояснение: Скрипт загрузится только когда секция комментариев появится в зоне видимости. Экономит трафик и ускоряет начальную загрузку.