Загрузка и последовательность выполнения веб-страницы?


244

Я сделал несколько веб-проектов, но я не слишком много думаю о последовательности загрузки и выполнения обычной веб-страницы. Но теперь мне нужно знать детали. Трудно найти ответы от Google или SO, поэтому я создал этот вопрос.

Пример страницы выглядит так:

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

Итак, вот мои вопросы:

  1. Как загружается эта страница?
  2. Какова последовательность загрузки?
  3. Когда выполняется код JS? (встроенный и внешний)
  4. Когда выполняется CSS (применяется)?
  5. Когда исполняется $ (document) .ready?
  6. Будет ли загружен abc.jpg? Или это просто скачать kkk.png?

У меня есть следующее понимание:

  1. Браузер сначала загружает HTML (DOM).
  2. Браузер начинает загружать внешние ресурсы сверху вниз, строка за строкой.
  3. Если a <script>выполнено, загрузка будет заблокирована и дождется загрузки и выполнения файла JS, а затем продолжится.
  4. Другие ресурсы (CSS / изображения) загружаются параллельно и выполняются при необходимости (например, CSS).

Или это так:

Браузер анализирует HTML (DOM) и получает внешние ресурсы в виде массива или структуры, подобной стеку. После загрузки HTML браузер начинает загружать внешние ресурсы в структуре параллельно и выполнять до тех пор, пока не будут загружены все ресурсы. Затем DOM будет изменен в соответствии с поведением пользователя в зависимости от JS.

Может ли кто-нибудь дать подробное объяснение того, что происходит, когда вы получите ответ HTML-страницы? Отличается ли это в разных браузерах? Любая ссылка на этот вопрос?

Спасибо.

РЕДАКТИРОВАТЬ:

Я провел эксперимент в Firefox с Firebug. И это показывает как следующее изображение: альтернативный текст


11
Стив Соудерс проделал большую работу в этой области. Google для Стива + Соудерс + высокая + производительность и посмотрите.
anddoutoi

3
Я не имею в виду настройку производительности. Я хочу знать детали.
Чжу Тао

2
Читая его работу, моё понимание того, как «это» работает в деталях, увеличилось в десять раз, так что это все еще действительный комментарий. Авторские права не позволяют мне цитировать здесь всю его книгу, поэтому я все же предлагаю вам посмотреть его работу.
anddoutoi

3
Отличное описание порядка вещей происходит здесь
Gerrat

Ответы:


277

Согласно вашему образцу,

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

Примерно поток выполнения выглядит следующим образом:

  1. Документ HTML загружается
  2. Начинается разбор HTML-документа
  3. Разбор HTML достигает <script src="jquery.js" ...
  4. jquery.js загружается и анализируется
  5. Разбор HTML достигает <script src="abc.js" ...
  6. abc.js загружается, анализируется и запускается
  7. Разбор HTML достигает <link href="abc.css" ...
  8. abc.css загружается и анализируется
  9. Разбор HTML достигает <style>...</style>
  10. Внутренние правила CSS анализируются и определяются
  11. Разбор HTML достигает <script>...</script>
  12. Внутренний Javascript анализируется и запускается
  13. Разбор HTML достигает <img src="abc.jpg" ...
  14. abc.jpg загружается и отображается
  15. Разбор HTML достигает <script src="kkk.js" ...
  16. kkk.js загружается, анализируется и запускается
  17. Разбор HTML-документа заканчивается

Обратите внимание, что загрузка может быть асинхронной и неблокируемой из-за поведения браузера. Например, в Firefox есть этот параметр, который ограничивает количество одновременных запросов на домен.

Также в зависимости от того, был ли компонент уже кэширован или нет, этот компонент может не запрашиваться снова в запросе ближайшего будущего. Если компонент был кэширован, он будет загружен из кеша вместо фактического URL.

Когда анализ завершен, а документ готов и загружен, запускаются события onload. Таким образом, когда onloadуволен, $("#img").attr("src","kkk.png");запускается. Так:

  1. Документ готов, загрузка загружена.
  2. Хиты исполнения Javascript $("#img").attr("src", "kkk.png");
  3. kkk.png загружается и загружается в #img

$(document).ready()Событие на самом деле это событие срабатывает , когда все компоненты страницы загружаются и готовы. Подробнее об этом читайте: http://docs.jquery.com/Tutorials:Introduction_$ (документ) .ready ()

Редактировать - эта часть более подробно описывает параллельную или нет:

По умолчанию и, насколько я понимаю, браузер обычно запускает каждую страницу тремя способами: анализатор HTML, Javascript / DOM и CSS.

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

Например, когда парсер встречает эту строку:

<a href="#" onclick="alert('test');return false;" style="font-weight:bold">a hypertext link</a>

Парсер сделает 3 вызова, два в Javascript и один в CSS. Во-первых, анализатор создаст этот элемент и зарегистрирует его в пространстве имен DOM вместе со всеми атрибутами, связанными с этим элементом. Во-вторых, будет вызван синтаксический анализатор, чтобы связать событие onclick с этим конкретным элементом. Наконец, он сделает еще один вызов в потоке CSS, чтобы применить стиль CSS к этому конкретному элементу.

Исполнение сверху вниз и однопоточное. Javascript может выглядеть многопоточным, но дело в том, что Javascript является однопоточным. Вот почему при загрузке внешнего файла JavaScript разбор основной HTML-страницы приостанавливается.

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

Элемент будет доступен в DOM только после его анализа. Таким образом, при работе с конкретным элементом скрипт всегда помещается после или внутри события onload окна.

Такой скрипт вызовет ошибку (в jQuery):

<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>
<div id="mydiv">Hello World</div>

Потому что, когда скрипт анализируется, #mydivэлемент все еще не определен. Вместо этого это будет работать:

<div id="mydiv">Hello World</div>
<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>

ИЛИ

<script type="text/javascript">/* <![CDATA[ */
  $(window).ready(function(){
                    alert($("#mydiv").html());
                  });
/* ]]> */</script>
<div id="mydiv">Hello World</div>

4
Спасибо. Но вы упомянули, что загрузка может быть асинхронной и неблокирующей из-за поведения браузера , так какие компоненты можно загружать в асин (например, FF в качестве примера)? <script>будет блокировать другие компоненты, верно? Любая ссылка о спецификации для каждого браузера?
Чжу Тао

4
$ (document) .ready () запускается по завершении DOM, а не при загрузке всех компонентов страницы
Pierre

2
@Pierre под компонентами страницы я имел в виду DOM -> любые компоненты в DOM.
Mauris

3
просто чтобы уточнить ... обычный window.onload происходит после # 17 ... так при каком # запускается код jquery $ (document) .ready ()? # 12? но сам DOM загружен на # 1, верно?
Armyofda12mnkeys

1
Если на вкладке <body> добавить тег <link href = "bootstrap.min.css" rel = "stylesheet" /> между тегами <img> и <script>, то img не отображается до тех пор, пока не будет загружен bootrap ... так что я думаю, что шаг [13], [14] нуждается в модификации ... кто-то может объяснить это поведение?
Бхуван

34

1) HTML загружен.

2) HTML анализируется постепенно. При получении запроса на актив браузер пытается загрузить ресурс. Конфигурация по умолчанию для большинства HTTP-серверов и большинства браузеров заключается в параллельной обработке только двух запросов. IE можно перенастроить, чтобы загружать неограниченное количество ресурсов параллельно. Стив Соудерс смог загрузить более 100 запросов параллельно в IE. Исключением является то, что запросы скриптов блокируют параллельные запросы ресурсов в IE. Вот почему настоятельно рекомендуется поместить весь JavaScript во внешние файлы JavaScript и поместить запрос непосредственно перед закрывающим тегом body в HTML.

3) После разбора HTML-кода DOM отображается. CSS отображается параллельно с отображением DOM почти во всех пользовательских агентах. В результате настоятельно рекомендуется поместить весь код CSS во внешние файлы CSS, которые запрашиваются как можно выше в разделе <head> </ head> документа. В противном случае страница обрабатывается до появления позиции запроса CSS в DOM, а затем рендеринг начинается сверху.

4) Только после полной визуализации DOM и разрешения всех ресурсов на странице либо по истечении времени ожидания JavaScript выполняется из события onload. IE7, и я не уверен насчет IE8, быстро не активирует ресурсы, если на запрос ресурса не получен HTTP-ответ. Это означает, что актив, запрашиваемый JavaScript, встроенным в страницу, то есть JavaScript, записанный в теги HTML, который не содержится в функции, может на несколько часов препятствовать выполнению события onload. Эта проблема может быть вызвана, если такой встроенный код существует на странице и не выполняется из-за столкновения пространства имен, которое вызывает сбой кода.

Из вышеперечисленных шагов наиболее ресурсоемким является анализ DOM / CSS. Если вы хотите, чтобы ваша страница обрабатывалась быстрее, напишите эффективный CSS, исключив избыточные инструкции и объединив инструкции CSS в наименьшее количество ссылок на элементы. Уменьшение количества узлов в вашем DOM-дереве также приведет к более быстрому рендерингу.

Имейте в виду, что каждый ресурс, который вы запрашиваете из вашего HTML или даже из ваших ресурсов CSS / JavaScript, запрашивается с отдельным заголовком HTTP. Это потребляет пропускную способность и требует обработки для каждого запроса. Если вы хотите, чтобы ваша страница загружалась как можно быстрее, уменьшите количество HTTP-запросов и уменьшите размер вашего HTML. Вы не оказываете никакой помощи пользователю, усредняя вес страницы в 180 Кб только из HTML. Многие разработчики соглашаются с ошибкой, заключающейся в том, что пользователь принимает решение о качестве контента на странице за 6 наносекунд, а затем удаляет DNS-запрос со своего сервера и записывает свой компьютер, если он недоволен, поэтому вместо этого они предоставляют самую красивую страницу на 250 тыс. HTML. Сделайте ваш HTML коротким и приятным, чтобы пользователь мог быстрее загружать ваши страницы.


2
Консолидация CSS-инструкций в наименьшее количество ссылок на элементы Звучит странно. Если мне нужно стилизовать три элемента, мне нужно сослаться ровно на три элемента. Я не могу отнести один к стилю десять, я могу? Или подробно об этом
Green

12

Откройте свою страницу в Firefox и получите аддон HTTPFox. Он расскажет вам все, что вам нужно.

Нашел это в архиве.incuito:

http://archivist.incutio.com/viewlist/css-discuss/76444

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

Когда он находит ссылку на внешнюю сущность, такую ​​как файл CSS, файл изображения, файл сценария, файл Flash или что-либо еще, внешнее по отношению к странице (либо на том же сервере / домене, либо нет), он готовится выполнить еще один запрос GET для этого ресурса.

Однако стандарт HTTP указывает, что браузер не должен делать более двух одновременных запросов к одному домену. Таким образом, он помещает каждый запрос в определенный домен в очереди, и, когда возвращается каждый объект, он запускает следующий в очереди для этого домена.

Время, необходимое для возврата объекта, зависит от его размера, нагрузки, которую сервер испытывает в настоящее время, и активности каждой отдельной машины между машиной, на которой запущен браузер, и сервером. Список этих машин в принципе может быть разным для каждого запроса, поскольку одно изображение может перемещаться из США ко мне в Великобританию через Атлантику, а другое с того же сервера выходит через Тихий океан, Азию и Европу, что занимает больше времени. Таким образом, вы можете получить последовательность, подобную следующей, где страница имеет (в этом порядке) ссылки на три файла сценария и пять файлов изображений, все различающихся размеров:

  1. ПОЛУЧИТЬ script1 и script2; запрос очереди для script3 и images1-5.
  2. script2 прибывает (это меньше, чем script1): GET script3, очередь images1-5.
  3. script1 прибывает; ПОЛУЧИТЬ image1, очередь изображений2-5.
  4. image1 прибывает, ПОЛУЧИТЕ image2, очередь images3-5.
  5. script3 не может прибыть из-за проблемы с сетью - GET script3 снова (автоматическая повторная попытка).
  6. image2 прибывает, script3 все еще не здесь; ПОЛУЧИТЬ image3, очередь изображений4-5.
  7. изображение 3 прибывает; ПОЛУЧИТЬ image4, очередь image5, script3 еще в пути.
  8. image4 прибывает, ПОЛУЧИТЕ image5;
  9. изображение5 прибывает.
  10. script3 прибывает.

Короче говоря: любой старый порядок, в зависимости от того, что делает сервер, что делает остальная часть интернета, и есть ли какие-либо ошибки или нет, и их нужно повторно выбрать. Это может показаться странным способом ведения дел, но было бы буквально невозможно для Интернета (не только для WWW) работать с какой-либо степенью надежности, если бы это не было сделано таким образом.

Кроме того, внутренняя очередь браузера может не извлекать объекты в порядке их появления на странице - это не требуется ни по одному стандарту.

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



2

AFAIK, браузер (по крайней мере, Firefox) запрашивает каждый ресурс, как только он его анализирует. Если он встречает тег img, он запросит это изображение, как только тег img будет проанализирован. И это может произойти даже до того, как он получит весь документ HTML ... то есть он все еще может загружать документ HTML, когда это произойдет.

Для Firefox существуют очереди браузера, которые применяются в зависимости от того, как они установлены в about: config. Например, он не будет пытаться загрузить более 8 файлов одновременно с одного сервера ... дополнительные запросы будут поставлены в очередь. Я думаю, что есть ограничения для каждого домена, для каждого прокси-сервера и другие вещи, которые описаны на веб-сайте Mozilla и могут быть установлены в about: config. Я где-то читал, что IE не имеет таких ограничений.

Событие jQuery ready запускается сразу после загрузки основного HTML-документа и его анализа в DOM. Затем событие загрузки запускается после загрузки и анализа всех связанных ресурсов (CSS, изображений и т. Д.). Это ясно показано в документации по jQuery.

Если вы хотите контролировать порядок загрузки всего этого, я считаю, что наиболее надежный способ сделать это - использовать JavaScript.



1

Выбранный ответ, похоже, не относится к современным браузерам, по крайней мере, в Firefox 52. Я заметил, что запросы на загрузку ресурсов, таких как css, javascript, передаются, например, до того, как HTML-анализатор достигает элемента

<html>
  <head>
    <!-- prints the date before parsing and blocks HTMP parsering -->
    <script>
      console.log("start: " + (new Date()).toISOString());
      for(var i=0; i<1000000000; i++) {};
    </script>

    <script src="jquery.js" type="text/javascript"></script>
    <script src="abc.js" type="text/javascript"></script>
    <link rel="stylesheets" type="text/css" href="abc.css"></link>
    <style>h2{font-wight:bold;}</style>
    <script>
      $(document).ready(function(){
      $("#img").attr("src", "kkk.png");
     });
   </script>
 </head>
 <body>
   <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
   <script src="kkk.js" type="text/javascript"></script>
   </body>
</html>

Что я обнаружил, что время начала запросов на загрузку ресурсов CSS и JavaScript не были заблокированы. Похоже, что Firefox сканирует HTML и идентифицирует ключевые ресурсы (ресурс img не включен) перед началом анализа HTML.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.