Как работает <script defer = "defer" >?

У меня есть несколько элементов <script>, а код в некоторых из них зависит от кода в других элементах <script>. Я видел, что атрибут defer может пригодиться здесь, поскольку он позволяет отложить блокировку кода в процессе выполнения.

Чтобы проверить это, я выполнил это в Chrome: http://jsfiddle.net/xXZMN/.

<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>

Однако он предупреждает 2 - 1 - 3. Почему он не предупреждает 1 - 2 - 3?

Ответ 1

ОБНОВЛЕНО: 2/19/2016

Рассмотрите этот ответ устаревшим. См. Другие ответы в этом сообщении для информации, относящейся к более новой версии браузера.

=============================================== ==========

В основном, отсрочка говорит браузеру ждать "пока он не готов" перед выполнением javascript в этом блоке script. Обычно это после завершения DOM загрузки и document.readyState == 4

Атрибут defer специфичен для Internet Explorer. В Internet Explorer 8 в Windows 7 результат, который я вижу на тестовой странице JS Fiddle, составляет 1 - 2 - 3.

Результаты могут отличаться от браузера к браузеру.

http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx

Вопреки распространенному мнению, IE следует за стандартами чаще, чем люди позволяют, на самом деле атрибут "defer" определен в спецификации DOM Level 1 http://www.w3.org/TR/REC-DOM-Level-1/level-one-html.html

Определение W3C отложить: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer:

"При установке этот атрибут boolean дает подсказку пользовательскому агенту, что script не собирается создавать какой-либо контент документа (например, нет" document.write "в javascript), и, таким образом, пользовательский агент может продолжить разбор и рендеринг."

Ответ 2

Несколько фрагментов из спецификации HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Отложенные и асинхронные атрибуты должны не указывается, если атрибут src нет.


Существует три возможных режима: могут быть выбраны с использованием этих атрибуты [async и defer]. Если асинхронный атрибут присутствует, то script будет выполняется асинхронно, как только доступен. Если атрибут async нет, но атрибут отсрочки присутствует, то scriptвыполняется, когда страница завершена разбор. Если ни один атрибут не является присутствует, то выбирается scriptи выполняется немедленно, до Пользовательский агент продолжает разбор страницы.


Точные детали обработки для этих атрибуты, в основном для исторических причины, несколько нетривиальные, связанных с несколькими аспектами HTML. Требования к внедрению поэтому по необходимости рассеяны во всем описании. алгоритмы ниже (в этом разделе) описать ядро ​​этой обработки, но эти алгоритмы ссылаются и на которые ссылаются правила синтаксического анализа для script начальный и конечный теги в HTML, в внешний контент и XML, правила для метода document.write(), обработка сценариев и т.д.


Если элемент имеет атрибут src, и элемент имеет атрибут отсрочки, и элемент отмечен как "вставленный парсер", а элемент не имеет асинхронного атрибута:

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

Ответ 3

Реальный ответ: Потому что вы не можете доверять отсрочке.

В концепции отсрочка и асинхронность различаются следующим образом:

async позволяет script загружаться в фоновом режиме без блокировки. Затем, когда он заканчивает загрузку, рендеринг блокируется и выполняется script. Render возобновляет выполнение script.

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

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

  • В некоторых ситуациях у некоторых браузеров есть ошибка, из-за которой скрипты defer не работают.
  • Некоторые браузеры задерживают событие DOMContentLoaded до тех пор, пока не загрузятся сценарии defer, а некоторые нет.
  • Некоторые браузеры подчиняются defer на <script> элементам со встроенным кодом и без атрибута src, а некоторые игнорируют его.

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

<script defer async src="..."></script>

98% браузеров, используемых во всем мире, и 99% в США будут избегать блокировки с помощью этого подхода.

(Если вам нужно подождать, пока документ завершит разбор, прослушайте событие DOMContentLoaded или используйте удобную функцию jQuery .ready(). Вы все равно должны сделать это, чтобы грациозно отступить в браузерах, t реализовать defer вообще.)

Ответ 4

defer может использоваться только в теге <script> для включения внешнего script. Следовательно, рекомендуется использовать в <script> -tags в разделе <head>.

Ответ 5

Отложенный атрибут предназначен только для внешних скриптов (он должен использоваться только в том случае, если присутствует атрибут src).

Ответ 6

Следует также отметить, что при использовании script defer в определенных ситуациях могут быть проблемы в IE <= 9. Подробнее об этом: https://github.com/h5bp/lazyweb-requests/issues/42

Ответ 7

Как атрибут defer работает только с тегом скриптов с src. Нашел способ имитировать отсрочку для встроенных скриптов. Используйте событие DOMContentLoaded.

<script defer src="external-script.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
    // Your inline scripts which uses methods from external-scripts.
});
</script>

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

Ответ 8

Посмотрите на эту замечательную статью Глубокое погружение в мутные воды script загрузки разработчика Google Джейка Арчибальда, написанного в 2013 году.

Цитирование соответствующего раздела из этой статьи:

Перенести

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Spec говорит. Загружайте вместе, выполняйте команду непосредственно перед DOMContentLoaded. Игнорировать "отложить" на скриптах без "src".

IE < 10 говорит: я мог бы выполнить 2.js на полпути через выполнение 1.js. Разве это не весело?

Браузеры в красном говорят: я понятия не имею, что это за "отсрочка", я собираюсь загрузите скрипты, как если бы они там не были.

Другие браузеры говорят: Хорошо, но я не могу игнорировать "отложить" скрипты без "src".

(добавлю, что ранние версии Firefox запускают DOMContentLoaded до того, как скрипты defer закончатся, в соответствии с этим комментарием.)суб >

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

Ответ 9

Этот атрибут Boolean установлен для указания браузеру, что script предназначен для выполнения после того, как документ был проанализирован. Поскольку эта функция еще не реализована всеми другими основными браузерами, авторы не должны предполагать, что выполнение script s будет фактически отложено. Никогда не вызывайте document.write() из defer script (поскольку Gecko 1.9.2, это сдует документ). Атрибут defer не должен использоваться для скриптов, не имеющих атрибута src. Начиная с Gecko 1.9.2, атрибут defer игнорируется в сценариях, которые не имеют атрибута src. Однако в Gecko 1.9.1 даже встроенные скрипты откладываются, если установлен атрибут defer.

defer работает с хром, firefox, т.е. > 7 и Safari

ref: https://developer.mozilla.org/en-US/docs/HTML/Element/script

Ответ 10

Атрибут defer является логическим атрибутом.

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

Примечание. Отложенный атрибут предназначен только для внешних скриптов (он должен использоваться только в том случае, если присутствует атрибут src).

Примечание. Существует несколько способов выполнения внешнего script:

Если присутствует async: script выполняется асинхронно с остальной частью страницы (script будет выполняться, пока страница продолжит разбор) Если async отсутствует и присутствует отсрочка: script выполняется, когда страница закончила синтаксический анализ Если не присутствуют ни асинхронные, ни отсрочки: script извлекается и выполняется немедленно, прежде чем браузер продолжит анализ страницы