Ответ 1
Если вы не загружаете скрипты динамически или не помечаете их как defer
или async
, тогда скрипты загружаются в порядке, встречающемся на странице. Не имеет значения, является ли это внешним скриптом или встроенным скриптом - они выполняются в том порядке, в котором они встречаются на странице. Встроенные сценарии, которые приходят после внешних сценариев, сохраняются до тех пор, пока все внешние сценарии, предшествующие им, не загрузились и не запустились.
Асинхронные сценарии (независимо от того, как они указаны как асинхронные) загружаются и запускаются в непредсказуемом порядке. Браузер загружает их параллельно, и он может запускать их в любом порядке.
Там нет предсказуемого порядка среди нескольких асинхронных вещей. Если нужен предсказуемый порядок, его необходимо кодировать, регистрируя уведомления о загрузке из асинхронных сценариев и вручную упорядочивая вызовы javascript при загрузке соответствующих объектов.
Когда тег сценария вставляется динамически, поведение порядка выполнения будет зависеть от браузера. Вы можете увидеть, как Firefox ведет себя в этой справочной статье. Короче говоря, более новые версии Firefox по умолчанию динамически добавляют тег сценария для асинхронизации, если тег сценария не был установлен иначе.
Тег скрипта с async
может быть запущен сразу после загрузки. Фактически, браузер может приостановить синтаксический анализатор от всего, что он делал, и запустить этот скрипт. Таким образом, он действительно может работать практически в любое время. Если сценарий был кэширован, он может запуститься практически сразу. Если для загрузки скрипта требуется некоторое время, он может запуститься после того, как парсер завершит работу. С TG43 следует помнить одну вещь: он может работать в любое время, и это время не предсказуемо.
Тег сценария с defer
ждет, пока не будет выполнен весь синтаксический анализатор, а затем запускает все сценарии, отмеченные defer
, в том порядке, в котором они были обнаружены. Это позволяет пометить несколько сценариев, которые зависят друг от друга, как defer
. Все они будут отложены до тех пор, пока анализатор документов не будет завершен, но они будут выполняться в том порядке, в котором они были найдены, сохраняя свои зависимости. Я думаю о defer
как о том, что скрипты помещены в очередь, которая будет обработана после того, как парсер будет сделан. Технически браузер может загружать сценарии в фоновом режиме в любое время, но он не будет выполнять или блокировать синтаксический анализатор до тех пор, пока синтаксический анализатор не завершит синтаксический анализ страницы и синтаксический анализ и запуск любых встроенных сценариев, которые не отмечены defer
или async
.
Вот цитата из этой статьи:
сценарии с вставленными сценариями выполняются асинхронно в IE и WebKit, но синхронно в Opera и Firefox до 4.0.
Соответствующая часть спецификации HTML5 (для новых совместимых браузеров) здесь. Там много написано об асинхронном поведении. Очевидно, что эта спецификация не применяется к более старым браузерам (или браузерам с плохим подтверждением), поведение которых вам, вероятно, придется проверить, чтобы определить.
Цитата из спецификации HTML5:
Затем первый из следующих вариантов, который описывает ситуацию необходимо соблюдать:
Если элемент имеет атрибут src, а элемент имеет задержку атрибут, и элемент был помечен как "вставленный парсер", и элемент не имеет асинхронного атрибута Элемент должен быть добавлен до конца списка скриптов, которые будут выполняться, когда документ завершил анализ, связанный с документом синтаксического анализатора, который создал элемент.
Задача, которую источник сетевой задачи помещает в очередь задач один раз алгоритм извлечения завершен должен установить элемент "готов к быть "выполненным парсером". Парсер будет обрабатывать выполнение скрипта.
Если элемент имеет атрибут src и элемент помечен как "вставленный парсером", и элемент не имеет асинхронного атрибута Элементом является ожидающий сценарий синтаксического анализа документа синтаксический анализатор, который создал элемент. (Может быть только один такой сценарий для каждого документа за раз.)
Задача, которую источник сетевой задачи помещает в очередь задач один раз алгоритм извлечения завершен должен установить элемент "готов к быть "выполненным парсером". Парсер будет обрабатывать выполнение скрипта.
Если элемент не имеет атрибута src, и элемент был помечается как "вставленный парсер", а документ HTML-парсера или Синтаксический анализатор XML, создавший элемент script, имеет таблицу стилей, которая блокирующие сценарии Элемент является ожидающим сценарием блокировки-разбора Документ синтаксического анализатора, который создал элемент. (Там может только быть одним из таких сценариев на каждый документ.)
Установите элемент "готов к выполнению парсера". Парсер будет обрабатывать выполнение сценария.
Если элемент имеет атрибут src, не имеет атрибута async, и не имеет установленного флага "force-async" Элемент должен быть добавлен до конца списка скриптов, которые будут выполняться по порядку, как только насколько это возможно, связанные с документом элемента скрипта на время запуска алгоритма подготовки сценария.
Задача, которую источник сетевой задачи помещает в очередь задач один раз алгоритм извлечения завершен должен выполнить следующие шаги:
Если элемент не является первым элементом в списке скриптов который будет выполнен по порядку как можно скорее, к которому он был добавлен выше, пометьте элемент как готовый, но прервите эти шаги без выполнение сценария еще.
Выполнение: Выполнить блок сценария, соответствующий первому сценарию. элемент в этом списке скриптов, которые будут выполняться по порядку, как только возможно.
Удалите первый элемент из этого списка скриптов, которые будут выполняться чтобы как можно скорее.
Если это список скриптов, которые будут выполняться по порядку в кратчайшие сроки еще не пуста, и первая запись уже помечена как готово, затем вернитесь к шагу с меткой выполнения.
Если элемент имеет атрибут src Элемент должен быть добавлен в набор сценариев, которые будут выполняться в кратчайшие сроки документа элемента сценария в то время, когда алгоритм подготовки сценария начал.
Задача, которую источник сетевой задачи помещает в очередь задач один раз алгоритм извлечения завершен должен выполнить блок сценария и затем удалите элемент из набора сценариев, которые будут выполняться как как можно скорее.
В противном случае пользовательский агент должен немедленно выполнить блок скрипта, даже если другие сценарии уже выполняются.
А как насчет скриптов модуля Javascript, type="module"
?
Javascript теперь поддерживает загрузку модулей с помощью синтаксиса, подобного следующему:
<script type="module">
import {addTextToBody} from './utils.mjs';
addTextToBody('Modules are pretty cool.');
</script>
Или с атрибутом src
:
<script type="module" src="http://somedomain.com/somescript.mjs">
</script>
Все, сценарии с type="module"
автоматически получают атрибут defer
. Это загружает их параллельно (если не встроено) с другой загрузкой страницы, а затем запускает их по порядку, но после того, как анализатор завершен.
Сценариям модуля также может быть присвоен атрибут async
, который будет запускать встроенные сценарии модуля как можно скорее, не дожидаясь окончания синтаксического анализа и не ожидая запуска сценария async
в каком-либо определенном порядке относительно других сценариев.
Есть довольно полезная временная диаграмма, которая показывает выборку и выполнение различных комбинаций сценариев, включая сценарии модуля, здесь, в этой статье: Загрузка модуля Javascript.