Существует так много разных способов включить JavaScript в HTML-страницу. Я знаю о следующих вариантах:
- встроенный код или загруженный с внешнего URI
- включается в тег <head> или <body> [ 1 , 2 ]
- не имея ни одного,
defer
илиasync
атрибута (только внешние скрипты) - включается в статический источник или динамически добавляется другими скриптами (при разных состояниях разбора, разными методами)
Не считая скрипты браузера с жесткого диска, javascript: URIs и onEvent
-attributes [ 3 ], уже есть 16 альтернатив для запуска JS, и я уверен, что что-то забыл.
Меня не очень беспокоит быстрая (параллельная) загрузка, мне более интересно узнать порядок выполнения (который может зависеть от порядка загрузки и порядка документов ). Есть ли хорошая (кросс-браузерная) ссылка, которая охватывает действительно все случаи? Например http://www.websiteoptimization.com/speed/tweak/defer/ имеет дело только с 6 из них и тестирует в основном старые браузеры.
Поскольку я боюсь, что нет, вот мой конкретный вопрос: у меня есть некоторые (внешние) сценарии заголовка для инициализации и загрузки сценария. Затем у меня есть два статических встроенных скрипта в конце тела. Первый позволяет загрузчику скриптов динамически добавлять другой элемент скрипта (ссылающийся на внешние js) к телу. Второй из статических встроенных сценариев хочет использовать js из добавленного внешнего сценария. Может ли это зависеть от того, что другой был выполнен (и почему :-)?
источник
Ответы:
Если вы не загружаете скрипты динамически или не помечаете их как
defer
илиasync
, тогда скрипты загружаются в порядке, указанном на странице. Неважно, является ли это внешним скриптом или встроенным скриптом - они выполняются в порядке, в котором они встречаются на странице. Встроенные сценарии, которые идут после внешних сценариев, сохраняются до тех пор, пока все внешние сценарии, которые были до них, не загружены и запущены.Асинхронные сценарии (независимо от того, как они указаны как асинхронные) загружаются и выполняются в непредсказуемом порядке. Браузер загружает их параллельно, и он может запускать их в любом порядке.
Там нет предсказуемого порядка среди нескольких асинхронных вещей. Если требуется предсказуемый порядок, его необходимо кодировать путем регистрации уведомлений о загрузке из асинхронных сценариев и ручной последовательности вызовов javascript при загрузке соответствующих объектов.
Когда тег сценария вставляется динамически, поведение порядка выполнения будет зависеть от браузера. Вы можете увидеть, как Firefox ведет себя в этой справочной статье . Короче говоря, более новые версии Firefox по умолчанию динамически добавляют тег сценария к асинхронному, если тег сценария не был установлен иначе.
Тег скрипта с
async
может быть запущен, как только он будет загружен. Фактически, браузер может приостановить анализатор от всего, что он делал, и запустить этот скрипт. Таким образом, он действительно может работать практически в любое время. Если сценарий был кэширован, он может запуститься практически сразу. Если сценарий загружается некоторое время, он может запуститься после того, как анализатор завершит работу. Следует помнить одну вещьasync
: он может работать в любое время, и это время не предсказуемо.Тег сценария с
defer
ожиданием, пока не будет выполнен весь анализатор, а затем запускает все сценарии, помеченные знаком,defer
в том порядке, в котором они были обнаружены. Это позволяет пометить несколько сценариев, которые зависят друг от друга, какdefer
. Все они будут отложены до тех пор, пока анализатор документов не будет завершен, но они будут выполняться в том порядке, в котором они были найдены, сохраняя свои зависимости. Я думаю,defer
что сценарии помещаются в очередь, которая будет обработана после выполнения синтаксического анализа. Технически браузер может загружать сценарии в фоновом режиме в любое время, но он не будет выполнять или блокировать синтаксический анализатор до тех пор, пока синтаксический анализатор не завершит синтаксический анализ страницы и синтаксический анализ и запуск любых встроенных сценариев, которые не отмеченыdefer
илиasync
.Вот цитата из этой статьи:
Соответствующая часть спецификации HTML5 (для новых совместимых браузеров) здесь . Там много написано об асинхронном поведении. Очевидно, что эта спецификация не относится к более старым браузерам (или браузерам с плохой совместимостью), поведение которых вам, вероятно, придется проверить, чтобы определить.
Цитата из спецификации HTML5:
Как насчет скриптов модуля Javascript
type="module"
?Javascript теперь имеет поддержку загрузки модуля с синтаксисом, подобным этому:
Или с
src
атрибутом:Всем сценариям
type="module"
автоматически присваиваетсяdefer
атрибут. Это загружает их параллельно (если не встроено) с другой загрузкой страницы, а затем запускает их по порядку, но после того, как анализатор завершен.Скриптам модуля также может быть присвоен
async
атрибут, который будет запускать встроенные скрипты модуля как можно скорее, не дожидаясь окончания синтаксического анализа и не дожидаясь запускаasync
скрипта в каком-либо определенном порядке относительно других скриптов.Есть довольно полезная временная диаграмма, которая показывает выборку и выполнение различных комбинаций сценариев, включая сценарии модуля, здесь в этой статье: Загрузка модуля Javascript .
источник
defer
дает парсеру возможность начать его загрузку раньше, при этом все еще откладывая его выполнение. Обратите внимание, что если у вас много сценариев с одного и того же хоста, то более ранний запуск загрузки может фактически замедлить загрузку других с того же хоста (поскольку они конкурируют за пропускную способность), на котором ваша страница ожидает (но неdefer
), поэтому это может быть обоюдоострый меч.Браузер выполнит сценарии в порядке их поиска. Если вы вызываете внешний скрипт, он блокирует страницу, пока скрипт не будет загружен и выполнен.
Чтобы проверить этот факт:
Динамически добавленные сценарии выполняются, как только они добавляются в документ.
Чтобы проверить этот факт:
Порядок оповещений «добавлен» -> «Привет!» -> "финал"
Если в скрипте вы попытаетесь получить доступ к элементу, который еще не был достигнут (пример:),
<script>do something with #blah</script><div id="blah"></div>
то вы получите ошибку.В целом, да, вы можете включить внешние скрипты, а затем получить доступ к их функциям и переменным, но только если вы выйдете из текущего
<script>
тега и начнете новый.источник
Отличное резюме @addyosmani
Бесстыдно скопировано с https://addyosmani.com/blog/script-priorities/
источник
После тестирования многих опций я обнаружил, что следующее простое решение - загружать динамически загружаемые скрипты в порядке их добавления во все современные браузеры.
источник