НейроАгент

Где размещать теги script в HTML: Полное руководство

Узнайте оптимальное размещение тегов script для лучшей производительности. Изучите традиционные и современные подходы, атрибуты async/defer и лучшие практики для разных случаев использования.

Вопрос

Где размещать теги <script> в HTML-разметке?

При встраивании JavaScript в HTML-документ, в каком месте следует размещать теги <script> и включаемый JavaScript? Я помню, что не рекомендуется размещать их в секции <head>, но размещение в начале секции <body> тоже плохо, поскольку JavaScript должен быть обработан до полной отрисовки страницы. Это оставляет конец секции <body> в качестве логичного места для тегов <script>.

Так где же правильно размещать теги <script>?

(Примечание: Этот вопрос ссылается на связанное обсуждение о переносе вызовов JavaScript-функций из тегов <a> в теги <script>. Я использую jQuery, но также приветствуются общие ответы.)

НейроАгент

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

Содержание

Традиционные подходы к размещению скриптов

Размещение в конце секции <body>

Традиционный подход размещает теги <script> непосредственно перед закрывающим тегом </body>. Этот метод предотвращает блокировку начальной отрисовки страницы JavaScript, поскольку браузер сначала отрисовывает весь HTML-контент, а затем выполняет скрипты.

html
<!DOCTYPE html>
<html>
<head>
    <title>Моя страница</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <h1>Добро пожаловать на мою страницу</h1>
    <p>Этот контент загружается быстро.</p>
    
    <!-- Скрипты в конце body -->
    <script src="jquery.js"></script>
    <script src="app.js"></script>
</body>
</html>

Преимущества:

  • Быстрая отрисовка контента
  • Отсутствие поведения, блокирующего отрисовку
  • DOM-элементы доступны при выполнении скриптов

Размещение в начале секции <body>

Размещение скриптов в начале секции <body> обычно не рекомендуется, так как это блокирует отрисовку. Браузер должен загрузить и разобрать JavaScript, прежде чем продолжить отрисовку остального контента страницы.

html
<body>
    <!-- Плохая практика - блокирует отрисовку -->
    <script src="jquery.js"></script>
    <script src="app.js"></script>
    
    <h1>Добро пожаловать на мою страницу</h1>
    <p>Этот контент не появится, пока не загрузятся скрипты.</p>
</body>

В секции <head>

Хотя размещение скриптов в секции <head> блокирует отрисовку, существуют случаи, когда это необходимо, особенно для библиотек, которые должны загружаться до любого манипулирования DOM.

html
<head>
    <title>Моя страница</title>
    <script src="jquery.js"></script> <!-- Может быть необходимо здесь -->
</head>

Современные стратегии загрузки скриптов

Атрибуты Async и Defer

Современный HTML предоставляет атрибуты async и defer для управления поведением загрузки скриптов без перемещения их в конец документа.

Атрибут Async:

html
<script src="analytics.js" async></script>
  • Загружается без блокировки разбора
  • Выполняется сразу после завершения загрузки
  • Не гарантируется выполнение в порядке
  • Лучше для независимых скриптов, таких как аналитика

Атрибут Defer:

html
<script src="jquery.js" defer></script>
<script src="app.js" defer></script>
  • Загружается без блокировки разбора
  • Выполняется после завершения разбора документа
  • Сохраняет порядок выполнения
  • Лучше для зависимых скриптов

Модульные скрипты

Модули ES6 могут использовать атрибут type="module", который автоматически применяет отложенную загрузку:

html
<script type="module" src="main.js"></script>

Соображения по производительности

Поведение, блокирующее отрисовку

  • Без async/defer: Скрипты блокируют отрисовку независимо от размещения
  • С async/defer: Скрипты загружаются асинхронно, но могут все равно блокировать отрисовку в определенных условиях
  • Критический путь отрисовки: Понимание процесса отрисовки браузера помогает оптимизировать размещение скриптов

Влияние загрузки на Largest Contentful Paint (LCP)

  • Скрипты, блокирующие отрисовку, могут значительно повлиять на оценки LCP
  • Некритические скрипты должны загружаться после элементов LCP
  • Рассмотрите возможность использования loading="lazy" для необязательных скриптов
html
<script src="non-critical-feature.js" loading="lazy"></script>

Рекомендации, специфичные для jQuery

Загрузка jQuery перед зависимыми скриптами

При использовании jQuery убедитесь, что он загружается перед любыми зависимыми скриптами:

html
<!-- Вариант 1: С defer -->
<script src="jquery.js" defer></script>
<script src="my-jquery-code.js" defer></script>

<!-- Вариант 2: В конце body -->
<body>
    <!-- Контент страницы -->
    <script src="jquery.js"></script>
    <script src="my-jquery-code.js"></script>
</body>

Размещение jQuery CDN

jQuery часто загружается из CDN. Современные CDN поддерживают функции, такие как preconnect и DNS-prefetch:

html
<head>
    <link rel="preconnect" href="https://code.jquery.com">
    <link rel="dns-prefetch" href="https://code.jquery.com">
    <script src="https://code.jquery.com/jquery-3.7.1.min.js" 
            integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" 
            crossorigin="anonymous"></script>
</head>

Лучшие практики в зависимости от случая использования

Критические скрипты

  • Используйте встроенный в <head> с async для критической функциональности
  • Рассмотрите возможность размещения критического JavaScript в <head> с defer
html
<head>
    <script>
        // Критический встроенный скрипт
        function criticalFunction() {
            // Необходимая функциональность
        }
    </script>
    <script src="critical-library.js" defer></script>
</head>

Сторонние скрипты

  • Используйте async для независимых сторонних скриптов (аналитика, реклама)
  • Используйте defer для скриптов, зависящих от DOM или других скриптов

Приложенческие скрипты

  • Используйте defer для большинства приложенческих скриптов JavaScript
  • Размещайте в конце <body>, если не используются атрибуты async/defer

Продвинутые техники оптимизации

Подсказки ресурсов

Реализуйте подсказки ресурсов для оптимизации загрузки скриптов:

html
<head>
    <!-- Preconnect к CDN -->
    <link rel="preconnect" href="https://cdn.example.com">
    
    <!-- DNS prefetch для домена -->
    <link rel="dns-prefetch" href="https://cdn.example.com">
    
    <!-- Preload критических скриптов -->
    <link rel="preload" href="critical.js" as="script">
</head>

Динамическая загрузка скриптов

Загружайте скрипты динамически при необходимости:

javascript
function loadScript(src, callback) {
    const script = document.createElement('script');
    script.src = src;
    script.onload = callback;
    document.body.appendChild(script);
}

// Загрузка некритического скрипта после взаимодействия со страницей
document.addEventListener('click', () => {
    loadScript('interactive-feature.js', () => {
        // Инициализация функции
    });
});

Бандлинг скриптов и разделение кода

  • Объединяйте связанные скрипты вместе
  • Реализуйте разделение кода для больших приложений
  • Используйте современные сборщики, такие как Webpack, Rollup или Vite

Мониторинг производительности

Мониторьте производительность загрузки скриптов:

html
<script>
    // Мониторинг производительности
    window.addEventListener('load', () => {
        const loadTime = performance.now();
        console.log('Страница загружена за:', loadTime, 'мс');
    });
</script>

Заключение

Оптимальное размещение тегов <script> в HTML значительно эволюционировало вместе с современными практиками веб-разработки. Хотя размещение скриптов в конце <body> остается жизнеспособным подходом, атрибуты async и defer обеспечивают большую гибкость и лучшую производительность. Для приложений jQuery убедитесь, что библиотека загружается перед зависимыми скриптами, и рассмотрите возможность использования современных стратегий загрузки. Лучший подход зависит от вашего конкретного случая использования, требований к производительности и критичности ваших скриптов. Всегда тестируйте и измеряйте влияние ваших решений по размещению скриптов на реальные показатели производительности.