Как браузеры анализируют html?

HTML
Как браузеры анализируют html?

Когда мы входим в юридическуюurl, сначала браузерDNSРазрешение доменного имени, после получения IP-адреса сервера браузер отправляет серверуGETЗапросите, подождите, пока сервер вернется в нормальное состояние, а браузер начнет загрузку и парсинг.html. Здесь только кратко описан процесс парсинга html браузером.

htmlСтраница в основном состоит изdom,css,javascriptи другие части, в том числеcssа такжеjavascriptобе内联так же может быть脚本Представлено в виде курсаhtmlможет также представитьimg,iframeи другие ресурсы. На самом деле все эти ресурсыdomФорма тега встроена вhtmlстранице, поэтому эта статья обобщаетhtmlПроцесс синтаксического анализаdomпроцесс разбора.

1 domпроцесс разбора

весьdomПроцесс синтаксического анализа顺序,а также渐进式из.

顺序Это относится к началу с первой строки и анализу строки за строкой;渐进式Это означает, что браузеру не терпится отобразить завершенную часть парсинга.Если мы проведем следующий эксперимент, мы обнаружим, что в断点первыйdivОн уже отображается в браузере:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <div>
        first div
    </div>
    <script>
        debugger
    </script>
    <div>
        second div
    </div>
</body>
</html>

теперь, когдаdomРазбирается по порядку с первой строки, так что как судитьdomКогда разбор закончен? Этот вопрос следует часто задавать на собеседованиях, например:

window.onloadа такжеDOMContentLoadedКакая разница?

Я просто хотел посмотреть, понял ли яdom树Когда сборка завершена, вопрос действительно важен, особенно несколько лет назад.jqueryстек технологий, потому что мы используемjavascriptдействоватьdomили датьdomСвязывание событий имеет предварительное условие, которое должно бытьdom树был создан. весьhtmlстраницыdomКогда разбор завершен,dom树Сборка завершена. После того, как дом построенdocumentОбъект отправляет событияDOMContentLoadedставить в известностьdom树Сборка завершена.

htmlНачните парсинг с первой строки и столкнетесь外联ресурс(外联css,外联javascript,image,iframeи т. д.) запросит соответствующий ресурс, затем процесс заблокируется, если будет запрошенdomпроцесс разбора? Ответ зависит от ситуации, какие-то ресурсы будут, а какие-то нет. Следующее разделено на две категории в зависимости от того, будет ли он блокировать синтаксический анализ страницы:阻塞型а также非阻塞型, обратите внимание, что флаги, которые различают два типа ресурсов,documentотправка объектаDOMContentLoadedМомент времени события, считающегося отправленнымDOMContentLoadedтолько событиеdom树Сборка завершена.

1.1 Блокировка

заблокируетdomПроанализированные ресурсы в основном включают:

  • встроенный css
  • встроенный JavaScript
  • Контур простого javascript
  • Аутрич отложить javascript
  • Контур css перед тегом javascript

ОхватjavascriptМожно использоватьasyncа такжеdeferПоэтому он делится на три категории:外联普通javascript,外联defer javascript,外联async javascript, эти виды охватаjavascriptПодробности приведены далее в этой статье.domвстретились при разборе外联普通javascriptПарсинг будет приостановлен и запрос будет полученjavascriptи выполнить, затем продолжить синтаксический анализdom树.

для外联defer javascriptЗдесь мы сосредоточимся на том, почему это также приписывается阻塞型. Как упоминалось ранее, здесьdocumentотправка объектаDOMContentLoadedсобытие для идентификацииdom树сборка завершена, иdefer javascriptОн запрашивается и выполняется до отправки события, поэтому он также классифицируется как блокирующий, но вам нужно знать,deferизjavascriptпо фактуdom树Сборка и отправкаDOMContentLoadedОн запрашивается и выполняется между событиями, но если понимать это по-другому,<script>сам тожеdomотчасти нетрудно понять, почемуdeferизjavascriptБудет вDOMContentLoadedВыполняется перед отправкой.

Также обратите внимание, чтоjavascript标签之前的外联css. На самом деле сказаноcssРесурс не должен блокироватьdom树процесса сборки, в конце концовcssвлияет толькоdomстиль, не влияетdomструктура,MDNНа это так поясняется:

The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.

Но реальность таковаdom树Сборка подлежитjavascriptблокировка, покаjavascriptПри выполнении вы можете использовать что-то вродеWindow.getComputedStyle()API, такие какdomстили, такие как:

const para = document.querySelector('p');
const compStyles = window.getComputedStyle(para);

Поэтому браузеры обычно сталкиваются с<script>этикетка перед этикеткой外联cssЗапрошено и выполнено. Но обратите внимание, что здесь добавлено предварительное условиеjavascript标签之前的外联css, что означает, чтоjavascriptзависит от исполнения外联css. Этот легко упускаемый моментэта статьяТакже есть инструкции, рекомендуемые к прочтению.

Эти阻塞型После того, как запрос ресурса выполнен и выполненdom树Разбор завершен, тогдаdocumentобъект будет отправленDOMContentLoadedсобытие, сказалdom树Сборка завершена.

1.2 Неблокирующий

не блокируетdomПроанализированные ресурсы в основном включают:

  • Контур css после тега javascript
  • image
  • iframe
  • Схема асинхронного javascript

dom树Будет отправлен после завершения синтаксического анализаDOMContentLoadedсобытие, для外联cssРесурсы делятся на две категории, одна находится в<script>Перед меткой класс располагается по адресу<script>после этикетки. роды<script>после этикетки外联cssне блокируетdom树аналитический.外联cssправильноdom树Влияние процесса синтаксического анализа описано в очень хорошей статье здесь:DOMContentLoaded and stylesheets, рекомендуется к прочтению.

DOMContentLoadedсобытие для идентификацииdom树После того, как сборка завершена, как судить о других非阻塞型Загрузка ресурса завершена? ответwindow.onload. Поскольку событие отправляется слишком поздно, в нормальных условиях оно нам не нужно, но болееDOMContentLoadedдействовать как можно скорееdom.

а такжеimage,iframeтак же как外联async javascriptне будет блокироватьdomСтроительство дерева. здесь外联async javascriptЧто это такое? В следующем разделе будет представлена ​​общая外联javascript.

2 外联javascriptпроцесс загрузки

htmlможно импортировать на страницу内联javascript, также можно ввести外联javascript,外联javascriptРазделен на:

  • Контур простого javascript
<script src="indx.js"></script>
  • Аутрич отложить javascript
<script defer src="indx.js"></script>
  • Схема асинхронного javascript
<script async src="indx.js"></script>

Первый из них外联普通javascript, будет блокироватьhtmlанализ,htmlКаждый раз, когда вы сталкиваетесь с таким<script>Тег будет запрошен и выполнен, как показано на рисунке ниже, зеленый означаетhtmlРазбор; серым цветомhtmlСинтаксический анализ приостановлен; синий указывает外联javascriptЗагрузка; розовый указываетjavascript执行.

标记
да外联普通javascriptПроцесс выполнения загрузки выглядит следующим образом:
外联普通javascript
второй外联defer javascriptнемного отличается,htmlвстретились при разборе<script>Метка не блокирует парсинг, а будет временно храниться в очереди, ожидая полногоhtmlПосле завершения синтаксического анализа запрос и выполнение в порядке очередиjavascript, но это外联defer javascriptОн будет отправлен после того, как все загружено и выполненоDOMContentLoadedмероприятие,外联defer javascriptПроцесс выполнения загрузки выглядит следующим образом:
外联defer javascript
третий外联async javascriptне блокируетhtmlПроцесс парсинга, обратите внимание на упомянутый здесь скрипт下载Процесс не блокируетсяhtmlРазбираем, если загрузка завершенаhtmlЕсли парсинг не завершен, он будет приостановленhtmlРазбор, первое выполнение после завершения загрузкиjavascriptкод для продолжения синтаксического анализаhtml, процесс выглядит следующим образом:
外联async javascript
но еслиhtmlбыл проанализирован,外联async javascriptЕсли загрузка не была завершена, она не будет заблокированаDOMContentLoadedрассылка событий. следовательно外联async javascriptОчень вероятно, что будет слишком поздно контролироватьDOMContentLoadedсобытия, такие какstackoverflowВверхЭта проблема.

Обратите внимание, что эти цифры взяты изздесь.

3 DOMContentLoadedПроблемы совместимости

DOMContentLoadedпервоначальноfirefoxПредлагается, чтобы другие браузеры сочли его очень полезным и начали поддерживать его один за другим, но функции немного отличаются, напримерoperaсерединаjavascriptКазнь не ждет外联cssнагрузка. доHTML5выйдетDOMContentLoadedстандартизированный, согласноHTML5стандарт,javascriptПеред выполнением скрипт появляется в текущем<script>предыдущий<link rel="stylesheet">Должен быть полностью загружен.

Итак, как решить эту проблему до того, как все браузеры будут стандартизированыDOMContentLoadedА проблемы с совместимостью? может относиться кjQueryсередина.ready()Для реализации метода в интернете уже много разборов исходников этого метода, я не буду здесь разбирать, а сразу объясню принцип. На самом деле он используетсяMDN: DOMContentLoadedМетод совместимости, описанный в ,ie9только что начал поддерживатьDOMContentedLoaded,ie8среда может быть обнаруженаdocument.readystateстатус для подтвержденияdom树Завершена ли сборка.document.readystateВключает 3 состояния:

  • loading - загружается html-документ
  • интерактивный — HTML-документ загружен и проанализирован, но ресурсы, такие как изображения, не загружены, что эквивалентноDOMContentLoaded
  • Complete - загружены все ресурсы, что эквивалентноwindow onload

Поэтому мы судимdocument.readystateстатусinteractiveимитироватьDOMContentLoadedмомент времени. Но здесь следует отметить, что.ready()Возьмем метод в качестве примера, мы можем вызвать его в следующих местах:

  • встроенный JavaScript
  • Контур простого javascript
  • Аутрич отложить javascript
  • Схема асинхронного javascript

3 из них непосредственно судят в трех местахdocument.readystateОпределенно естьloadingстатус, только外联async javascriptможет появитьсяdocument.readystateдляinteractiveилиcompletedсостояние, потому что外联async javascriptне блокируетdomпарсится, так что для полного покрытия предыдущих 4 случаев нужно мониторитьdocument.readystateИзменение:

if (document.readystate === 'interactive'
    || document.readystate === 'complete') {
        // 调用ready回调函数
} else {
    document.onreadystatechange = function () {
        if (document.readystate === 'interative') {
            // 调用ready回调函数
        }
    } 
}

4 Цитаты

В основном обратитесь к следующим статьям, рекомендуемым к прочтению:

  1. Page lifecycle: DOMContentLoaded, load, beforeunload, unload
  2. DOMContentLoaded and stylesheets
  3. тег скрипта: асинхронные и отложенные атрибуты
  4. MDN: DOMContentLoaded
  5. MDN: readystatechange
  6. Замените Ready() jQuery на обычный JavaScript