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

Я сделал несколько веб-проектов, но я не слишком много думаю о последовательности загрузки и выполнения обычной веб-страницы. Но теперь мне нужно знать детали. Трудно найти ответы от 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. Если <script> выполнено, загрузка будет заблокирована, дождитесь загрузки и выполнения файла JS, а затем продолжите.
  4. Другие ресурсы (CSS/ изображения) загружаются параллельно и выполняются при необходимости (например, CSS).

Или это так:

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

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

Благодарю.

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

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

7 ответов

Решение

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

<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:Introducing_$(document).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>

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

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

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

Откройте свою страницу в 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) было бы буквально невозможно работать с какой-либо степенью надежности, если бы это не было сделано таким образом.

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

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

Если вы спрашиваете об этом, потому что хотите ускорить свой веб-сайт, загляните на страницу Yahoo, посвященную рекомендациям по ускорению вашего веб-сайта. У этого есть много лучших методов для ускорения Вашего веб-сайта.

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

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

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

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

Dynatrace AJAX Edition показывает точную последовательность загрузки, анализа и выполнения страницы.

Выбранный ответ, похоже, не относится к современным браузерам, по крайней мере, в 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.

Другие вопросы по тегам