Тег сценария - асинхронный и отложенный


548

У меня есть несколько вопросов по поводу атрибутов asyncи deferдля <script>тега , который к моему пониманию работы только в HTML5 браузеров.

На одном из моих сайтов есть два внешних файла JavaScript, которые в данный момент находятся над </body>тегом; во-первых Источник от Google, а второй является локальным внешним скриптом.

С учетом скорости загрузки сайта

  1. Есть ли какое-то преимущество в добавлении asyncк двум сценариям, которые у меня есть внизу страницы?

  2. Будет ли какое-то преимущество в добавлении asyncопции к двум сценариям и размещении их в верхней части страницы в <head>?

  3. Означает ли это, что они загружаются при загрузке страницы?
  4. Я предполагаю, что это вызовет задержки для браузеров HTML4, но ускорит ли это загрузку страниц для браузеров HTML5?

С помощью <script defer src=...

  1. Повлияет ли загрузка двух скриптов внутри <head>с атрибутом так deferже, как и ранее </body>?
  2. Еще раз я предполагаю, что это замедлит работу браузеров HTML4.

С помощью <script async src=...

Если у меня есть два сценария с asyncвключенным

  1. Будут ли они загружать в то же время?
  2. Или по одному с остальной частью страницы?
  3. Порядок сценариев становится проблемой? Например, один сценарий зависит от другого, поэтому, если один загружается быстрее, второй может выполняться некорректно и т. Д.

Наконец, лучше ли мне оставить все как есть до тех пор, пока HTML5 не станет более распространенным?


5
asyncявляется новым (ish), но deferбыл частью IE начиная с IE4. deferбыл добавлен в другие браузеры гораздо позже, но старые версии этих браузеров, как правило, гораздо меньше.
Alohci

3
Теперь HTML5 стал очень популярным!
сентября

2
deferэто то же самое, что размещать скрипты в нижней части HTML, что было обычным явлением на протяжении многих лет.
vsync

1
@vsync не обязательно имеет значение true, браузер будет загружать JS с тегом defer при анализе тега сценария, но будет откладывать выполнение до тех пор, пока не будет DOMContentLoaded. Скачивание неблокирующее. Размещение в нижней части HTML-кода задержит загрузку и выполнение JS, пока не будет создан DOM, но вы все равно будете подвергаться дополнительной задержке, ожидая загрузки.
Брэд Фрост

@BradFrost - загрузка, на мой взгляд, блокирует, в том смысле, что она использует пропускную способность интернета, и для тех, у кого медленное соединение, я считаю обязательным сначала загрузить документ и только потом, когда он будет отрендерен, начать скачивать файлы javascript , Это верно в тех случаях, когда содержимое не тесно связано с JavaScript для рендеринга всего (например, SPA )
vsync

Ответы:


406

Сохраняйте свои сценарии прямо раньше </body>. Асинхронность может использоваться со сценариями, расположенными там, в нескольких случаях (см. Обсуждение ниже). Отсрочка не будет иметь большого значения для сценариев, расположенных там, потому что работа по анализу DOM в значительной степени уже выполнена в любом случае.

Вот статья, которая объясняет разницу между async и defer: http://peter.sh/experiment/asynchronous-and-deferred-javascript-execution-explained/ .

Ваш HTML будет отображаться быстрее в старых браузерах, если вы сохраняете скрипты в конце тела прямо перед этим </body>. Таким образом, чтобы сохранить скорость загрузки в старых браузерах, не нужно размещать их где-либо еще.

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

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

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

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


8
Defer должен по-прежнему запускать их по порядку, но запускать до dom-contentloaded. Разве это не означает, что положить его в голову будет быстрее, так как он может начать загружать их ДО ТОГО, как анализируется тело html?
Кевин

9
Вы сказали, что вставлять скрипты headи устанавливать их deferне будет быстрее, чем ставить их раньше </body>, но из того, что я прочитал, это неправильно. Подумайте об этом - если вы вставите сценарии <head>, они начнут загружаться немедленно, тогда как, если они верны, </body>то все остальные элементы загружаются первыми.
Nate

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

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

2
На данный момент требование </ body> на самом деле не является обязательным для браузерных разработок с 2012 года, когда был опубликован этот ответ.
bgcode

845

Это изображение объясняет обычные теги сценария, асинхронные и отложенные

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

  • Асинхронные сценарии выполняются сразу после загрузки сценария, поэтому он не гарантирует порядок выполнения (сценарий, который вы включили в конце, может выполняться до первого файла сценария)

  • Отложенные сценарии гарантируют порядок выполнения, в котором они появляются на странице.

Ссылка на эту ссылку: http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html


Я думаю, что пример с несколькими сценариями был бы лучше иллюстрировать их последовательность
vsync

4
@writofmandamus Похоже async, победит. См. Stackoverflow.com/questions/13821151/…
Монсеньор

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

@BhavikHirani Согласно этому сайту , использование async и defer в одном и том же теге скрипта использует async, если браузер поддерживает его, или использует отложенный режим, если он не поддерживает async, но поддерживает defer. Поведение довольно разное, поэтому я бы не советовал использовать оба, так как результат непредсказуем и может стать отличным источником ошибок.
Адриан Вийк

@arni Только в том случае, если полоса пропускания используется полностью, что бывает редко. И обе загрузки будут разделять пропускную способность, а не блокировать одну. - Далее: эти изображения показывают анализ зеленым, а не загрузку.
Роберт Симер

213

HTML5: async,defer

В HTML5 вы можете указать браузеру, когда запускать код JavaScript. Есть 3 варианта:

<script       src="myscript.js"></script>

<script async src="myscript.js"></script>

<script defer src="myscript.js"></script>
  1. Без asyncили defer, браузер немедленно запустит ваш сценарий, прежде чем отображать элементы, которые находятся ниже тега сценария.

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

  3. С помощью deferбраузера браузер запустит ваш скрипт, когда страница закончит анализ. (Не обязательно заканчивать загрузку всех файлов изображений. Это хорошо.)


Шаблон blogger.com требуется async=""до того, как он подтвердит и сохранит изменения шаблона.
noobninja

1
Примечание: нет никакой гарантии, что скрипты будут работать в порядке, указанном с помощью Async. «Так что, если ваш второй скрипт зависит от первого, избегайте Async».
Фейсал Насир

2
async- Сценарии выполняются в момент их загрузки, без учета их порядка в файле HTML.
vsync

30

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

Разница между asyncи deferвокруг, когда сценарий выполняется. Каждый asyncскрипт выполняется при первой возможности после завершения загрузки и до события загрузки окна. Это означает, что возможно (и вероятно), что asyncсценарии не выполняются в том порядке, в котором они встречаются на странице. В то время как deferсценарии, с другой стороны, гарантированно выполняются в том порядке, в каком они встречаются на странице. Это выполнение начинается после того, как синтаксический анализ полностью завершен, но до DOMContentLoadedсобытия документа .

Источник и дальнейшие подробности: здесь .


25

Столкнулся с такой же проблемой и теперь ясно понял, как оба будут работать. Надеюсь, эта ссылка будет полезна ...

асинхронный

Когда вы добавите атрибут async в тег сценария, произойдет следующее.

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
  1. Делайте параллельные запросы на получение файлов.
  2. Продолжайте анализ документа, как если бы он никогда не прерывался.
  3. Выполните отдельные сценарии в момент загрузки файлов.

Перенести

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

<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
  1. Делайте параллельные запросы на выборку отдельных файлов.
  2. Продолжайте анализ документа, как если бы он никогда не прерывался.
  3. Завершите анализ документа, даже если загружены файлы сценариев.
  4. Выполните каждый скрипт в том порядке, в котором они встречались в документе.

Ссылка: разница между асинхронным и отложенным


7

asyncи deferзагрузит файл во время анализа HTML. Оба не будут прерывать парсер.

  • Скрипт с asyncатрибутом будет выполнен после его загрузки. Пока скрипт с deferатрибутом будет выполнен после завершения анализа DOM.

  • Загруженные скрипты asyncне гарантируют какой-либо порядок. В то время как скрипты, загруженные с deferатрибутом, поддерживают порядок, в котором они появляются в DOM.

Используйте, <script async>когда скрипт не полагается ни на что. когда сценарий зависит от использования.

Лучшее решение было бы добавить в нижней части тела. Там не будет никаких проблем с блокировкой или рендерингом.


Просто хочу кое-что прояснить здесь, здесь происходят две вещи: 1. Загрузка ресурса 2. Выполнение ресурса. Загрузка ресурса в обоих случаях (async и defer) не блокируется, то есть они не блокируют синтаксический анализ html, в то время как выполнение в async блокирует синтаксический анализ, а в случае отсрочки выполнение происходит после анализа разметки html, следовательно, не блокирует в этом случае.
августа

5

Я думаю, что Джейк Арчибальд представил нам некоторые идеи еще в 2013 году, которые могут добавить еще больше позитива к теме:

https://www.html5rocks.com/en/tutorials/speed/script-loading/

У Святого Грааля есть набор скриптов, загружаемых немедленно, без блокировки рендеринга, и выполняются как можно скорее в порядке их добавления. К сожалению, HTML ненавидит вас и не позволит вам сделать это.

(...)

Ответ на самом деле в спецификации HTML5, хотя он скрыт внизу раздела загрузки скриптов. « Атрибут async IDL определяет, будет ли элемент выполняться асинхронно или нет. Если установлен флаг« force-async »элемента, то при получении атрибут асинхронного IDL должен возвращать true, а при установке -« force-async » флаг должен быть сначала сброшен ... ".

(...)

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

[
    '//other-domain.com/1.js',
    '2.js'
].forEach(function(src) {
    var script = document.createElement('script');
    script.src = src;
    script.async = false;
    document.head.appendChild(script);
});

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

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

Тем не менее, это может быть не самый быстрый способ загрузки скриптов:

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

Мы можем добавить обнаруживаемость обратно, поместив это в заголовок документа:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

Это говорит браузеру, что странице нужны 1.js и 2.js. link [rel = subresource] похож на link [rel = prefetch], но с другой семантикой. К сожалению, в настоящее время он поддерживается только в Chrome, и вам нужно объявить, какие скрипты загружать дважды, один раз с помощью элементов ссылки и снова в вашем скрипте.

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


1

Кажется, что поведение defer и async зависит от браузера, по крайней мере, на этапе выполнения. ЗАМЕЧАНИЕ: отсрочка распространяется только на внешние скрипты. Я предполагаю, что async следует той же схеме.

В IE 11 и ниже порядок выглядит следующим образом:

  • асинхронный (может частично выполняться при загрузке страницы)
  • нет (может выполняться во время загрузки страницы)
  • defer (выполняется после загрузки страницы, все откладываются в порядке размещения в файле)

В Edge, Webkit и т. Д. Атрибут async игнорируется или помещается в конец:

  • data-pagespeed-no-defer (выполняется перед любыми другими скриптами, пока страница загружается)
  • нет (может выполняться во время загрузки страницы)
  • отложить (ожидает загрузки DOM, все отложить в порядке размещения в файле)
  • асинхронный (кажется, ждет загрузки DOM)

В более новых браузерах атрибут data-pagespeed-no-defer запускается перед любыми другими внешними сценариями. Это для сценариев, которые не зависят от DOM.

ПРИМЕЧАНИЕ. Используйте defer, если вам нужен явный порядок выполнения ваших внешних скриптов. Это говорит браузеру выполнить все отложенные сценарии в порядке размещения в файле.

В сторону: размер внешних javascript-скриптов имел значение при загрузке ... но не влиял на порядок выполнения.

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


data-pagespeed-no-deferявляется атрибутом, используемым модулем PageSpeed ​​на стороне сервера . Атрибут на это сам не имеет никакого эффекта в любом браузере. data-pagespeed-no-defer
Qtax
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.