Ответ 1
Что означают defer
и async
?
По умолчанию тег <script src=...></script>
является злым!. Браузер должен останавливать разбор HTML до тех пор, пока script не будет загружен и не запущен (поскольку script может вызвать document.write(...)
или определить глобальные переменные, от которых зависят последующие скрипты). Это означает, что никакие изображения и таблицы стилей, которые после тега script не запускаются, до тех пор, пока script не завершит загрузку и выполнение. Внешние скрипты обычно делают загрузку в Интернете намного медленнее, поэтому NoScript стал настолько популярным.
Microsoft представила defer
для решения проблемы. Если вы используете <script defer src=...></script>
, вы обещаете не называть document.write(...)
. A defer
внешний script начнет загрузку немедленно, но не будет выполняться до тех пор, пока страница не будет отображаться. После рендеринга страницы все скрипты defer
выполняются в том же порядке, в котором они были объявлены. Не все браузеры реализуют defer
.
HTML5 представил атрибут async
, который может выполняться в любое время - возможно, до того, как страница закончит синтаксический анализ или даже перед другими сценариями defer
/async
, которые все еще загружаются. Но сложнее использовать несколько скриптов async
, потому что их порядок выполнения не гарантируется. Как и defer
, не все браузеры реализуют async
.
После выполнения всех defer
и async
сценариев срабатывают события DOMContentLoaded
и load
.
Краткая история defer
и async
- 1997 IE 4 вводит
defer
. - 1998 HTML 4 spec упоминает
defer
, но, к сожалению, он не говорит точно, когда выполняются сценарииdefer
(Все в порядке Доonload
?). Таким образом, никакие другие браузеры не реализуютdefer
, потому что никто не хочет реверсировать поведение IE IE или нарушать скрипты, которые могут зависеть от особенностей IE. (См. запрос функции Mozilla, например). - В 2006 году в проекте HTML5 подробно описываются детали, необходимые для реализации сценариев
defer
:defer
, которые должны выполняться в порядке после того, как остальная часть страницы будет проанализирована, и доonload
. Он также вводитasync
для указания скриптов, которые могут выполняться всякий раз, когда они загружаются без необходимости ждать друг друга. К сожалению, HTML5 противоречит IE, не разрешая встроенные скриптыdefer
. Этот ломает инвариант, что все сценарииdefer
выполняются по порядку (если у некоторыхdefer
сценариев естьsrc
, а у некоторых есть встроенное содержимое). - 2009 Gecko 1.9.1 (Firefox 3.5) поддерживает
defer
. - 2010-01 Gecko 1.9.2 (Firefox 3.6) поддерживает
async
. - 2010-09
defer
иasync
отмечены в Webkit. Вы должны увидеть его в Chrome и Safari очень скоро (он уже находится в канале Chrome dev, но он немного глючит). - Мы все еще ждем, когда Opera реализует
defer
иasync
, а IE - для реализацииasync
.
Итак, что должен использовать веб-разработчик?
В это время нет единого правила. Вы должны выбрать решение, которое наилучшим образом упрощает простоту, латентность отображения страницы и script задержка выполнения для набора браузеров, которые обращаются к вашему веб-сайту.
- Самый простой способ сделать рендеринг страницы перед выполнением скриптов, как указывали другие, - это разместить ваши скрипты в нижней части страницы. Но если сценарии необходимы, или веб-страница содержит много HTML, то вы должны поместить свои скрипты выше на странице.
- Если ваш script является автономным, а ваши клиенты используют IE или новые версии Firefox, используйте
<script async defer src=...></script>
: Это позволяет рендерингу продолжать параллельно с загрузкой script для IE и новейших браузеров HTML5, но вызывает pre-HTML5 браузеров (включая все версии Opera) для блокировки. - Если один внешний script зависит от другого, отметьте их как
defer
(но неasync
), и они будут выполнены в том порядке, в котором они были объявлены (кроме IE <= 9 в определенных условиях может выполнять их не по порядку). Опять же, это позволяет рендерингу продолжать параллельно с загрузкой script в IE и HTML5 с поддержкой Gecko/Webkit, но пострадают более старые браузеры и Opera. Рекомендуется использоватьdefer
, даже если скрипты находятся в нижней части страницы, чтобы они загружались параллельно друг другу. - Никогда не используйте
defer
для встроенных скриптов, потому что черновик HTML5 отменил гарантию выполнения выполнения. - Если ваша аудитория включает в себя многих Opera или старых пользователей Firefox/Safari, следующий фрагмент будет выполнять script после разбора документа в большинстве браузеров pre-HTML5 (IE, Webkit, нужно протестировать старый Firefox), а самый новый HTML5-браузеры начинают загрузку сразу, но не будут блокировать выполнение script из-за атрибута
async
. Другими словами, большинство старых браузеров рассматривают его как script в нижней части страницы, а новейшие браузеры распознаютasync
. Но пользователи Opera получают наихудшее из обоих миров, потому что Opera начинает исполнение сразу и не понимаетasync
. Это шаблон рекомендованный Google Analytics для ежа на многих веб-страницах.
сниппет:
<script>
(function() {
var script = document.createElement('script');
script.src = '...';
script.async = true;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(script, s);
})();
</script>
- Если другой script зависит от загрузки первого script, то вы можете использовать тот же шаблон, что и выше, но прослушайте событие onload первого элемента script перед выполнением второго script. См. пример LABjs для ожидания загрузки другого script.
- Если у вас несколько сценариев со сложными зависимостями, используйте LAB.js или YUI Loader, чтобы загрузить их параллельно и выполнить в некотором допустимом порядке.
- Если вы используете популярную библиотеку, такую как jQuery, подумайте об использовании Google copy вместо собственного, чтобы увеличить вероятность того, что браузер уже кэшировал его.
Обновление. Если у вас есть сценарии, разделенные на модули и желающие повысить производительность, я рекомендую Стиву Саудеру "Сцепление асинхронных скриптов" на "Даже быстрых сайтах". Он содержит советы/рекомендации для не только управления порядком выполнения, но и задержки анализа скриптов для повышения производительности.