Где я должен поместить теги <script> в разметку HTML?


1488

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

Так, где это правильное место , чтобы поставить <script>метки?

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


в случае, если вы просто ищете простое решение и используете какой-то серверный генератор, например Jekyll, я рекомендую вместо этого включить скрипт. намного проще!
Cregox

Ответы:


1864

Вот что происходит, когда браузер загружает сайт с <script>тегом на нем:

  1. Получить страницу HTML (например, index.html)
  2. Начните разбор HTML
  3. Синтаксический анализатор обнаруживает <script>тег, ссылающийся на внешний файл сценария.
  4. Браузер запрашивает файл скрипта. Тем временем парсер блокирует и прекращает анализ другого HTML-кода на вашей странице.
  5. Через некоторое время скрипт загружается и впоследствии выполняется.
  6. Парсер продолжает анализ остальной части HTML-документа.

Шаг № 4 вызывает плохой пользовательский опыт. Ваш сайт в основном перестает загружаться, пока вы не загрузите все скрипты. Если есть одна вещь, которую пользователи ненавидят, это ждет загрузки сайта.

Почему это вообще происходит?

Любой скрипт может вставить свой собственный HTML с помощью document.write()или других манипуляций с DOM. Это подразумевает, что синтаксический анализатор должен ждать, пока скрипт не будет загружен и выполнен, прежде чем он сможет безопасно проанализировать остальную часть документа. В конце концов, скрипт мог вставить свой собственный HTML в документ.

Однако большинство разработчиков JavaScript больше не манипулируют DOM во время загрузки документа. Вместо этого они ждут, пока документ не будет загружен, прежде чем изменять его. Например:

<!-- index.html -->
<html>
    <head>
        <title>My Page</title>
        <script src="my-script.js"></script>
    </head>
    <body>
        <div id="user-greeting">Welcome back, user</div>
    </body>
</html>

Javascript:

// my-script.js
document.addEventListener("DOMContentLoaded", function() { 
    // this function runs when the DOM is ready, i.e. when the document has been parsed
    document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});

Поскольку ваш браузер не знает, что my-script.js не будет изменять документ, пока он не будет загружен и выполнен, синтаксический анализатор прекращает синтаксический анализ.

Устаревшая рекомендация

Старый подход к решению этой проблемы заключался в размещении <script>тегов внизу вашего <body>, потому что это гарантирует, что парсер не будет заблокирован до самого конца.

У этого подхода есть своя собственная проблема: браузер не может начать загрузку сценариев, пока весь документ не будет проанализирован. Для больших веб-сайтов с большими сценариями и таблицами стилей возможность загрузки сценария как можно скорее очень важна для производительности. Если ваш сайт не загружается в течение 2 секунд, люди перейдут на другой сайт.

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

Современный подход

Сегодня браузеры поддерживают asyncи deferатрибуты на скриптах. Эти атрибуты сообщают браузеру, что безопасно продолжать анализ во время загрузки скриптов.

асинхронной

<script src="path/to/script1.js" async></script>
<script src="path/to/script2.js" async></script>

Сценарии с атрибутом async выполняются асинхронно. Это означает, что скрипт выполняется сразу после его загрузки, не блокируя браузер.
Это означает, что сценарий 2 может быть загружен и выполнен до сценария 1.

Согласно http://caniuse.com/#feat=script-async , 97,78% всех браузеров поддерживают это.

Перенести

<script src="path/to/script1.js" defer></script>
<script src="path/to/script2.js" defer></script>

Сценарии с атрибутом defer выполняются по порядку (т. Е. Сначала сценарий 1, затем сценарий 2). Это также не блокирует браузер.

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

Согласно http://caniuse.com/#feat=script-defer , 97,79% всех браузеров поддерживают это. 98,06% поддерживают это хотя бы частично.

Важное замечание о совместимости браузера: в некоторых случаях IE <= 9 может выполнять отложенные сценарии не по порядку. Если вам нужно поддерживать эти браузеры, пожалуйста, прочитайте это в первую очередь!

Вывод

Текущий уровень техники заключается в том, чтобы помещать сценарии в <head>тег и использовать атрибуты asyncor defer. Это позволяет загружать ваши скрипты как можно быстрее, не блокируя ваш браузер.

Хорошо, что ваш сайт все равно должен корректно загружаться в 2% браузеров, которые не поддерживают эти атрибуты, в то время как другие 98% ускоряются.


63
Я удивлен, что никто не процитировал объяснение Google ... developers.google.com/speed/docs/insights/BlockingJS
Кейси Фальк,

6
Мне не ясно, что касается DOM, а что нет. Вы можете уточнить? Безопасно ли выполнять асинхронную загрузку на что-то вроде jquery.js?
Даг

7
@Doug Например, document.writeдействует на дом. Вопрос не в том, управляет ли сценарий dom, а в том, когда он это делает. Пока все манипуляции с dom происходят после того, как domreadyсобытие сработало, вы в порядке. jQuery - это библиотека, которая сама по себе не управляет и не должна манипулировать dom.
Барт

24
Этот ответ вводит в заблуждение. Современные браузеры не прекращают синтаксический анализ, когда достигают синхронного тега сценария, который может повлиять на HTML, они просто прекращают рендеринг / выполнение и продолжают оптимистический анализ, чтобы начать загрузку других ресурсов, которые, вероятно, будут запрашиваться впоследствии, если HTML не затронут.
Фабио Бельтрамини

40
Почему asyncи deferатрибуты не используются нигде? Я имею в виду, что я просмотрел много HTML-источников из Интернета, и нигде не вижу атрибутов asyncи defer. ...?
Джон CJ

239

Как раз перед закрывающим тегом тела, как указано на

http://developer.yahoo.com/performance/rules.html#js_bottom

Поместите сценарии внизу

Проблема, вызванная скриптами, заключается в том, что они блокируют параллельные загрузки. Спецификация HTTP / 1.1 предполагает, что браузеры загружают не более двух компонентов параллельно для каждого имени хоста. Если вы обслуживаете свои изображения с нескольких имен хостов, вы можете получить более двух загрузок параллельно. Однако во время загрузки сценария браузер не будет запускать другие загрузки, даже на разных именах хостов.


7
Согласился с концепцией и ее объяснением. Но что произойдет, если пользователь начнет играть со страницей? Предположим, у меня есть выпадающий список AJAX, который начнет загружаться после того, как страница появится пользователю, но пока она загружается, пользователь нажимает на нее! А что, если «действительно нетерпеливый» пользователь отправит форму?
Hemant Tank

9
@Hermant Старый комментарий, но вы можете сделать трюк, отключив поля по умолчанию, затем включив их, используя JS, когда DOM полностью загружен. Это то, что Facebook сейчас делает.
Новато

2
Только что проверил это с хромом, чтобы проверить, если это все то же самое. Это. Вы можете проверить разницу во времени загрузки страниц ваших браузеров здесь. stevesouders.com/cuzillion
cypher

46
Если это лучшая практика, почему переполнение стека включает все свои теги сценария в <head>? :-P
Филип

10
В некоторых случаях, особенно в местах с интенсивным использованием ajax, загрузка в голове может фактически привести к более быстрому времени загрузки. Смотрите: encosia.com/dont-let-jquerys-document-ready-slow-you-down (обратите внимание, что функция «live ()» устарела в jquery, но статья по-прежнему применяется с «on ()» или « делегат "функция). Загрузка в <head> также может потребоваться для обеспечения правильного поведения, как указано @Hermant. Наконец, modernizr.com/docs рекомендует размещать свои скрипты в <head> по причинам, объясненным на его сайте.
Натан

77

Неблокирующие теги скрипта могут быть размещены где угодно:

<script src="script.js" async></script>
<script src="script.js" defer></script>
<script src="script.js" async defer></script>
  • async скрипт будет выполняться асинхронно, как только он станет доступен
  • defer скрипт выполняется по окончании разбора документа
  • async defer скрипт возвращается к отложенному поведению, если асинхронность не поддерживается

Такие сценарии будут выполняться асинхронно / после того, как документ будет готов, что означает, что вы не можете сделать это:

<script src="jquery.js" async></script>
<script>jQuery(something);</script>
<!--
  * might throw "jQuery is not defined" error
  * defer will not work either
-->

Или это:

<script src="document.write(something).js" async></script>
<!--
  * might issue "cannot write into document from an asynchronous script" warning
  * defer will not work either
-->

Или это:

<script src="jquery.js" async></script>
<script src="jQuery(something).js" async></script>
<!--
  * might throw "jQuery is not defined" error (no guarantee which script runs first)
  * defer will work in sane browsers
-->

Или это:

<script src="document.getElementById(header).js" async></script>
<div id="header"></div>
<!--
  * might not locate #header (script could fire before parser looks at the next line)
  * defer will work in sane browsers
-->

Сказав это, асинхронные сценарии предлагают следующие преимущества:

  • Параллельная загрузка ресурсов .
    Браузер может загружать таблицы стилей, изображения и другие сценарии параллельно, не дожидаясь загрузки и выполнения сценария.
  • Независимость порядка источника :
    Вы можете размещать скрипты внутри головы или тела, не беспокоясь о блокировке (полезно, если вы используете CMS). Порядок исполнения все еще имеет значение, хотя.

Можно обойти проблемы порядка выполнения с помощью внешних сценариев, поддерживающих обратные вызовы. Многие сторонние API JavaScript поддерживают неблокирующее выполнение. Вот пример загрузки API Карт Google в асинхронном режиме .


2
Это правильный ответ на сегодняшний день - использование этого подхода означает, что ваши виджеты легче держать самодостаточными, не нужно придумывать <head>логику включения.
Даниэль Соколовский

1
Я запутался , почему вы не можете использовать asyncили deferпри включении JQuery , как вы укажете в вашем втором блоке: <script src="jquery.js" async></script>. Вы можете объяснить, почему? Я подумал, что мне нужно иметь асинхронный тег для повышения производительности (согласно принятому ответу), чтобы моя страница могла загружаться даже во время загрузки jQuery]. Спасибо!
elbowlobstercowstand

3
@elbow в 99% случаев <script src=jquery.js>сопровождается $(function(){ ... })блоками где-то на странице. Асинхронная загрузка не гарантирует, что jQuery будет загружен в то время, когда браузер попытается проанализировать эти блоки, следовательно, это вызовет ошибку $ notfined error (вы можете не получить ошибку, если jQuery был загружен из кэша). Я ответил на вопрос о загрузке jQuery асинхронно и сохранить $(function(){ ... }). Я посмотрю, смогу ли я найти его, или вы можете посмотреть на этот вопрос: stackoverflow.com/q/14811471/87015
Salman A

1
@ SalmanA Спасибо! Да, я падаю на эти 99%. Сначала мне нужно jqueryзагрузить lib, затем мои оставшиеся .jsскрипты. Когда я объявляю asyncили deferна jqueryтеге сценария lib, мои .jsсценарии не работают. Я думал, $(function(){ ... })что защищал это - не думаю. Текущее решение: я не добавляю deferили asyncна jqueryLib сценарий, но я добавить asyncв моем РАЗВЕЙТЕ .jsсценарии. Примечание: причина я делаю какой - либо из этого, чтобы сделать Google Page Speed счастливым. Спасибо еще раз за помощь! Любой другой совет приветствуется. (Или ссылка на ваш предыдущий ответ). :)
elbowlobstercowstand

@elbow См. stackoverflow.com/a/21013975/87015 , это только даст вам идею, но не полное решение. Вместо этого вы можете искать «библиотеки асинхронного загрузчика jquery».
Салман

38

Стандартный совет, продвигаемый Yahoo! Команда «Исключительная производительность» должна размещать <script>теги в конце тела документа, чтобы они не блокировали отображение страницы.

Но есть несколько более новых подходов, которые предлагают лучшую производительность, как описано в этом ответе о времени загрузки файла Google Analytics JavaScript:

Стив Соудерс (эксперт по работе с клиентами) предлагает несколько отличных слайдов о:

  • Различные методы для загрузки внешних файлов JavaScript параллельно
  • их влияние на время загрузки и рендеринга страницы
  • какие индикаторы «в процессе» отображает браузер (например, «загрузка» в строке состояния, курсор мыши в виде песочных часов).

25

Если вы используете JQuery, поместите javascript в $(document).ready()любое удобное для вас место и используйте его, чтобы убедиться, что все загружено правильно перед выполнением каких-либо функций.

На заметку: мне нравятся все мои теги сценариев в <head>разделе, так как это кажется самым чистым местом.


14
в голове ... э? <header>?
Дэн Лугг

7
Обратите внимание, что использование $(document).ready()не означает, что вы можете поместить свой JavaScript куда угодно - вам все равно придется поместить его после того места, <script src=".../jquery.min.js">куда вы включили jQuery, чтобы он $существовал.
Рори О'Кейн

2
Не оптимально помещать теги скрипта в раздел <head> - это приведет к задержке отображения видимой части страницы, пока скрипты не будут загружены.
CyberMonk

Нет, @Dan, headerэлемент является частью содержимого документа HTML и должен встречаться один или несколько раз в теге head bodyэлемента . The для метаданных и данных, не относящихся к содержимому документа. Это, в эти дни, с deferи asyncидеальным местом для тегов сценария. headerэлементы должны содержать только информацию, которая описывает раздел документа, который следует за ним.
ProfK

1
@ProfK, Дэн имел в виду оригинальный неотредактированный вопрос, когда он опубликовал это более 4 лет назад. Как видите, вопрос был отредактирован год спустя.
kojow7

18

Современный подход в 2019 году - использование скриптов типа модуля ES6 .

<script type="module" src="..."></script>

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

Различия между скриптом и модулем описаны здесь:

https://stackoverflow.com/a/53821485/731548

Выполнение модуля по сравнению со сценарием описано здесь:

https://developers.google.com/web/fundamentals/primers/modules#defer

Поддержка показана здесь:

https://caniuse.com/#feat=es6-module


Хорошая информация для добавления в базу знаний
Сагар

1
Просто обратите внимание, что это не сработает, если вы просто пытаетесь что-то делать в своей локальной файловой системе без сервера. По крайней мере, в Chrome вы получаете ошибку перекрестного источника при попытке загрузить файлы js из HTML, даже если они оба имеют одинаковое происхождение - вашу файловую систему.
Hippietrail

11

XHTML не будет проверяться, если скрипт находится не в элементе head, а в другом месте. Оказывается, это может быть везде.

Вы можете отложить выполнение с помощью чего-то вроде jQuery, чтобы не имело значения, где оно находится (за исключением небольшого снижения производительности во время синтаксического анализа).


1
XHTML будет проверяться с помощью тегов скрипта в теле, как строгих, так и переходных. Однако теги стиля могут быть только в голове.
I.devries

11
<script src="myjs.js"></script>
</body>

Тег script должен всегда использоваться перед закрытием тела или Bottom в HTML- файле.

затем вы можете увидеть содержимое страницы перед загрузкой файла js .

проверьте это, если требуется: http://stevesouders.com/hpws/rule-js-bottom.php


2
Это на самом деле ответил на вопрос. Мне было интересно, что почти все опубликованные примеры никогда не давали должного визуального контекста «конца страницы»
Кен Ингрэм

1
Этот ответ очень обманчив и, скорее всего, неверен. Статьи в Google и в MDN предполагают, что синхронный JS (который здесь имеет место) всегда блокирует построение и анализ DOM, что приведет к задержке первого рендеринга. Таким образом, вы не можете видеть содержимое страницы, пока файл JS не будет извлечен и не завершится выполнение, независимо от того, где вы поместили файл JS в HTML-документ, если он синхронный
Lingaraju EV

Он также ссылается на замечания, сделанные в 2009 году и более не актуальны.
Toxaq

7

Обычный (и общепринятый) ответ - «внизу», потому что тогда весь DOM будет загружен, прежде чем что-либо сможет начать выполняться.

Существуют несогласные по разным причинам, начиная с имеющейся практики намеренного начала исполнения с события загрузки страницы.


6

Лучшее место , чтобы поместить <script>тег перед закрытием </body>тега , поэтому загрузки и выполнения не блокирует браузер для разбора HTML в документе,

Кроме загрузки JS файлов внешне имеют собственные преимущества , как это будет в кэше браузеров и может ускорить время загрузки страницы , он отделяет HTML и код JavaScript и помощь для управления базой коды лучше .

но современные браузеры также поддерживают некоторые другие оптимальные способы, такие как asyncи deferзагрузка внешних javascriptфайлов.

Асинхронный и отложенный

Обычно выполнение HTML-страницы начинается построчно. При обнаружении внешнего элемента JavaScript синтаксический анализ HTML останавливается до тех пор, пока JavaScript не будет загружен и готов к выполнению. Это нормальное выполнение страницы можно изменить с помощью deferи asyncатрибута.

Defer

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

<script src="/local-js-path/myScript.js" defer></script>

Async

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

<script src="/local-js-path/myScript.js" async></script>

Когда использовать какие атрибуты

  • Если ваш скрипт не зависит от других скриптов и является модульным, используйте async.
  • Если вы загружаете script1 и script2 с помощью async, оба будут работать
    параллельно с разбором HTML, как только они будут загружены
    и доступны.
  • Если ваш скрипт зависит от другого скрипта, используйте deferоба:
  • Когда script1 и script2 загружаются в этом порядке с помощью defer, тогда script1 гарантированно выполняется первым,
  • Тогда script2 будет выполняться после того, как script1 будет полностью выполнен.
  • Это необходимо сделать, если script2 зависит от script1.
  • Если ваш скрипт достаточно мал и зависит от другого типа asyncскрипта, используйте ваш скрипт без атрибутов и поместите его над всеми asyncскриптами.

ссылка: знаниеhills.com


3

Зависит от того, что если вы загружаете скрипт, необходимый для стилизации вашей страницы / используя действия на вашей странице (например, нажатие кнопки), то вам лучше разместить его сверху. Если ваш стиль на 100% CSS и у вас есть все запасные варианты для действий кнопок, вы можете поместить его внизу.

Или, что лучше (если это не проблема), вы можете создать модальное окно загрузки, поместить свой javascript внизу страницы и заставить его исчезнуть, когда будет загружена последняя строка вашего скрипта. Таким образом, вы можете избежать использования пользователями действий на вашей странице перед загрузкой скриптов. А также избегайте неправильной укладки.


3

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

включение сценариев в заголовок загружает сценарии заранее и может использоваться до загрузки всего веб-сайта.

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


2

В зависимости от сценария и его использования наилучшим возможным (с точки зрения загрузки страницы и времени рендеринга) может быть не использование обычного тега <script> как такового, а динамический запуск загрузки сценария асинхронно.

Есть несколько различных методов, но наиболее прямым является использование document.createElement ("script"), когда инициируется событие window.onload. Затем сценарий загружается первым после отображения самой страницы, что не влияет на время, в течение которого пользователь должен ждать появления страницы.

Это, естественно, требует, чтобы сам скрипт не использовался для рендеринга страницы.

Для получения дополнительной информации см. Пост Асинхронные сценарии сопряжения Стивом Соудерсом (создатель YSlow, но теперь в Google).


2
  • Если вы все еще заботитесь о поддержке и производительности в IE <10, лучше ВСЕГДА сделать так, чтобы ваш скрипт помечал последние теги вашего тела HTML. Таким образом, вы уверены, что остальная часть DOM была загружена, и вы не будете блокировать и рендеринг.

  • Если вас больше не волнует IE <10, возможно, вы захотите поместить свои скрипты в заголовок документа и использовать их, deferчтобы убедиться, что они запускаются только после загрузки DOM ( <script type="text/javascript" src="path/to/script1.js" defer></script>). Если вы все еще хотите, чтобы ваш код работал в IE <10, не забудьте обернуть ваш код в window.onloadчетное, хотя!


В принятом ответе это упоминается как «устаревшая рекомендация». Если вы по-прежнему имеете в виду это, вы, вероятно, должны предоставить какую-то ссылку, чтобы поддержать это.
Дакаб

1

Скрипт блокирует загрузку DOM, пока он не загружен и не выполнен.

Если вы помещаете скрипты в конец, то <body>все DOM имеет шанс загрузить и отобразить (страница будет «отображаться» быстрее). <script>будет иметь доступ ко всем этим элементам DOM.

С другой стороны, размещение его после <body>запуска или выше выполнит скрипт (там, где до сих пор нет элементов DOM).

Вы включаете jQuery, что означает, что вы можете разместить его где угодно и использовать .ready ()


1

Я думаю, что это зависит от исполнения веб-страницы. Если страница, которую вы хотите отобразить, не может отображаться должным образом без предварительной загрузки JavaScript, то сначала следует включить файл JavaScript. Но если вы можете отображать / отображать веб-страницу без первоначальной загрузки файла JavaScript, то вам следует поместить код JavaScript внизу страницы. Поскольку он будет эмулировать быструю загрузку страницы, и с точки зрения пользователя кажется, что эта страница загружается быстрее.


1

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


1

До конца тега body для предотвращения и блокировки пользовательского интерфейса.


-1

В конце HTML-документа

Так что это не повлияет на загрузку HTML-документа в браузере во время выполнения.


-1

Лучшее место для написания JavaScriptкода - в конце документа после или непосредственно перед </body>тегом, чтобы сначала загрузить документ, а затем выполнить код js.

<script> ... your code here ... </script>
</body>

А если вы напишете JQueryследующее, может быть в заголовке документа и он будет выполняться после загрузки документа:

<script>
$(document).ready(function(){
   //your code here...
});
</script>

это бросаетSyntaxError
Раз

Ваш ответ не был неправильным, но остро нуждался в обновлении.
Пол Карлтон

-2

Для меня имеет больше смысла включать скрипт после HTML. Потому что большую часть времени мне нужно загрузить Dom, прежде чем я выполню свой скрипт. Я мог бы поместить его в тег head, но мне не нравятся все издержки прослушивателя загрузки документов. Я хочу, чтобы мой код был коротким, приятным и легким для чтения.

Я слышал, что старые версии safari были странными при добавлении вашего скрипта вне тега head, но я говорю, кого это волнует. Я не знаю, чтобы кто-нибудь использовал эту старую чушь.

Хороший вопрос, кстати.


-6

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

Ситуация выглядит следующим образом:

Страница загружается линейно, «сверху вниз», поэтому, если вы поместите скрипт в заголовок, убедитесь, что он начинает загружаться раньше всего, теперь, если вы поместите его внутрь тела, смешанного с кодом, это может вызвать неприглядную загрузку страницы.

определить хорошую практику не зависит от того, где.

Чтобы поддержать вас, я упомяну следующее:

Вы можете разместить:

и страница будет загружаться линейно

страница загружается асинхронно с другим контентом

содержимое страницы будет загружено до и после завершения загрузки скрипты загружаются

Хорошей практикой здесь будет, когда будет реализовывать каждый?

Я надеюсь, что я был полезным, что-нибудь просто ответьте мне на этот вопрос.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.