Подтвердить что ты не робот

Отложенные сценарии выполняются перед событием DOMContentLoaded?

Отложенный от имени MDN говорит:

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

На DOMContentLoaded MDN также говорится:

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

Поэтому DOMContentLoaded запускается до того, как CSSOM будет готов. Это означает, что отложенные сценарии выполняются до того, как CSSOM будет готов. Но если это так, сценарии не должны иметь возможность получать правильные значения свойств CSS и не должны корректно применять CSS. Но это не так, мы знаем, что все отложенные сценарии работают хорошо.

  1. Так что документация MDN технически неверна?
  2. Где я могу найти официальную документацию DOMContentLoaded '? Я искал в https://dom.spec.whatwg.org/, но не смог найти его.

PS: пожалуйста, не говорите, что Google говорит, что CSSOM собирается перед выполнением любого встроенного JavaScript

enter image description here

Но гугл технически неверен. Встроенный JavaScript выполняется до того, как CSSOM будет готов. И из моих тестов я обнаружил, что MDN верен, и если js файлы (как отложенные, так и не отложенные) загружаются до css файлов (или js встроен), то js выполняется до готовности CSSOM. Так что js может некорректно обрабатывать стили. Чтобы избежать этого, нам нужна принудительная перекомпоновка перед всей логикой js.

Таким образом, если пользователь посещает наш веб-сайт со всеми необходимыми js, уже кэшированными и css не кэшированными, ИЛИ js загружается до css, тогда он может увидеть неправильно отображенную страницу. Чтобы избежать этого, мы должны добавить принудительный рефлоу во всех файлах js наших сайтов.

4b9b3361

Ответ 1

Я использую отложенную загрузку script. Было много технических объяснений от какого-то парня, который является известным гуру веб-сайта. Он ясно заявляет, что отложенный путь - это путь (по этой и той технической причине, подкрепленной всеми видами данных и графиков, что многие люди, казалось, чувствовали себя широко открытыми для обсуждения, re: async).

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

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

Так что, похоже, ваша документация верна. Эффект легко воспроизводится.

Как я могу выйти из него; самый простой способ:

<script src="css.bundle.js"></script>
<script src="vendor.bundle.js" defer></script>
<script src="angular.bundle.js" defer></script>
<script src="app.bundle.js" defer></script>

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

Итак, вы берете абсолютный минимальный CSS, необходимый для того, чтобы пинать приложение, создавать его как пакет и сначала загружать его, прежде всего. В противном случае вы можете объединить свои CSS на модуль/компонент и так далее.

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

Изменить: Увлекательно, ища эту ссылку (которую я еще не нашел), я прошел через несколько "экспертов" по ​​этому вопросу. Рекомендации сильно отличаются. Некоторые говорят, что асинск намного превосходит всех, некоторые говорят, что они откладывают. Жюри действительно похоже на эту тему, в целом я бы сказал, что, вероятно, это больше связано с тем, как вы создаете свои скрипты, чем на самом деле лучше других.

Изменить еще раз: вот еще несколько доказательств. Я запустил анализатор производительности на веб-сайте заглушки, используя вышеприведенную простую последовательность загрузки, преднамеренно делая скрипты наивными, чтобы они были видны на временной шкале.

Здесь SS результат: здесь есть четыре желтых прямоугольника. Первые три являются оценками скриптов. Четвертый (когда вы наводите на него инструмент в инструменте, это только помнит SS) - это событие DOMContentLoaded (одно с красным углом).

Загрузка/оценка скриптов перед событием DOMContentLoaded

Ответ 2

DOMContentLoaded может быть запущен перед CSSOM, source

Событие domContentLoaded запускается вскоре после разбора HTML; браузер не может блокировать JavaScript и, поскольку нет других скриптов блокировки синтаксического анализа, конструкция CSSOM также может продолжаться параллельно.

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

Статья в Google Developer описывает async вместо defer, но в случае вашего вопроса она ничего не меняет, потому что на основе Steve Статья с покупателями на perfplanet

Сценарии DEFER выполняются после DOM Interactive.

и его комментарий в его статье

[...] спецификация говорит, что сценарии DEFER выполняются после domInteractive, но до DOMContentLoaded.

Вы можете сделать свой собственный эксперимент, посмотрите ниже для кода, используя defer и временную шкалу

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.3/angular-material.css">
</head>
<body>
  <h1>App</h1>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.js" defer></script>
</body>
</html>

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

Ответ 3

Я действительно не читал спецификацию, хотя. Следующее основано на фактическом поведении Chrome (наблюдается на Chromium 68, Ubuntu). Поведение может отличаться в зависимости от браузера, если оно просто не определено в спецификации. Например, в 2010 году скрипты не всегда ждут продолжения таблиц стилей. Я предполагаю, что соглашения были достигнуты, и поведение было стандартизировано за эти годы.


В defer сценарии выполняются после того, как время domInteractive, до domContentLoaded; это последовательно.

domInteractive и domContentLoaded - это две временные метки, которые можно просмотреть на вкладке Производительность (ранее временная шкала) Chrome devtools. Возможно, также в других подобных инструментах, но я не пробовал.

domInteractive - это точка, когда анализ HTML и первоначальное построение DOM завершены (и все сценарии "sync" закончили выполняться). document.readyState меняется с 'loading' на 'interactive'; Событие readystatechange срабатывает на document соответственно.

Все defer сценарии выполняются в порядке их появления. Затем наступает domContentLoaded, а DOMContentLoaded срабатывает событие на document.

Конструкция DOM & CSSOM не зависит друг от друга; но сценарии синхронизации могут вводить зависимости.

Каждый сценарий синхронизации, внутренний или внешний, ожидает анализа предыдущих таблиц стилей (разумеется, после извлечения).

Да, сценарии синхронизации не блокируются последующими таблицами стилей. MDN, Google и другие статьи говорят, что "сценарии зависят от CSSOM, чтобы быть готовым"; они (вероятно) не упомянули, что только предыдущие части являются зависимыми.

PS: пожалуйста, не говорите, что Google говорит, что CSSOM собирается перед выполнением любого встроенного JavaScript

Google не сказал этого (по крайней мере, на момент, когда я прочитал эту статью).

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

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

Сценарии defer/async вообще не заботятся о таблицах стилей.

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

Различия между defer/async:

  • как указано выше, defer сценарии имеют предсказуемое время выполнения; ДОМ был готов. Их также обещают выполнить по порядку.

    Обновление: defer сценарии добавляются в конец списка, говорится в спецификации W3C (20-й пункт) defer scripts are added to the end of the list, said W3C's spec
    (также в спецификации WHATWG)

  • async сценарии не имеют обещаний относительно порядка выполнения; каждый async скрипт будет "поставлен в очередь на выполнение", как только он будет выбран; как только процесс рендеринга простаивает, они выполняются. (Точнее говоря, разные типы ресурсов имеют разные приоритеты. Спецификация содержит ценные требования)

Это должно хорошо объяснить два примера: первый async (от Google) и второй defer.


У меня нет большого опыта работы с CSSOM при загрузке страницы (хотя я работаю с DOM при загрузке страницы), поэтому не могу дать надежных советов. Кажется, может сработать "событие load в window " или "принудительное перезаполнение рано".