Загрузка и последовательность выполнения веб-страницы?
Я сделал несколько веб-проектов, но я не слишком много думаю о последовательности загрузки и выполнения обычной веб-страницы. Но теперь мне нужно знать детали. Трудно найти ответы от 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>
Итак, вот мои вопросы:
- Как загружается эта страница?
- Какова последовательность загрузки?
- Когда выполняется код JS? (встроенный и внешний)
- Когда выполняется CSS (применяется)?
- Когда исполняется $(document).ready?
- Будет ли загружен abc.jpg? Или это просто скачать kkk.png?
У меня есть следующее понимание:
- Браузер сначала загружает HTML (DOM).
- Браузер начинает загружать внешние ресурсы сверху вниз, строка за строкой.
- Если
<script>
выполнено, загрузка будет заблокирована, дождитесь загрузки и выполнения файла JS, а затем продолжите. - Другие ресурсы (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>
Примерно поток выполнения выглядит следующим образом:
- Документ HTML загружается
- Начинается разбор HTML-документа
- Разбор HTML достигает
<script src="jquery.js" ...
jquery.js
загружается и анализируется- HTML разбора достигает
<script src="abc.js" ...
abc.js
загружается, анализируется и запускается- HTML разбора достигает
<link href="abc.css" ...
abc.css
загружается и анализируется- HTML разбора достигает
<style>...</style>
- Внутренние правила CSS анализируются и определяются
- HTML разбора достигает
<script>...</script>
- Внутренний Javascript анализируется и запускается
- Разбор HTML достигает
<img src="abc.jpg" ...
abc.jpg
загружается и отображается- Разбор HTML достигает
<script src="kkk.js" ...
kkk.js
загружается, анализируется и запускается- Разбор HTML-документа заканчивается
Обратите внимание, что загрузка может быть асинхронной и неблокируемой из-за поведения браузера. Например, в Firefox есть этот параметр, который ограничивает количество одновременных запросов на домен.
Также в зависимости от того, был ли компонент уже кэширован или нет, этот компонент может не быть запрошен снова в запросе ближайшего будущего. Если компонент был кэширован, он будет загружен из кеша вместо фактического URL.
Когда анализ завершен, а документ готов и загружен, события onload
уволен. Таким образом, когда onload
уволен $("#img").attr("src","kkk.png");
это запустить. Так:
- Документ готов, загрузка загружена.
- Хиты исполнения Javascript
$("#img").attr("src", "kkk.png");
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, которые запрашиваются как можно выше в разделе
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 коротким и приятным, чтобы пользователь мог быстрее загружать ваши страницы. Ничто не улучшает пользовательский опыт, как быстрая и отзывчивая веб-страница.
Откройте свою страницу в Firefox и получите аддон HTTPFox. Он скажет вам все, что вам нужно.
Нашел это в архиве.incuito:
http://archivist.incutio.com/viewlist/css-discuss/76444
Когда вы впервые запрашиваете страницу, ваш браузер отправляет запрос GET на сервер, который возвращает HTML в браузер. Затем браузер начинает анализ страницы (возможно, до того, как все это будет возвращено).
Когда он находит ссылку на внешнюю сущность, такую как файл CSS, файл изображения, файл сценария, файл Flash или что-либо еще, внешнее по отношению к странице (либо на том же сервере / домене, либо нет), он готовится выполнить еще один запрос GET для этого ресурса.
Однако стандарт HTTP указывает, что браузер не должен делать более двух одновременных запросов к одному домену. Таким образом, он помещает каждый запрос в определенный домен в очереди, и, когда возвращается каждый объект, он запускает следующий в очереди для этого домена.
Время, необходимое для возврата объекта, зависит от его размера, нагрузки, которую испытывает сервер в данный момент, и активности каждой отдельной машины между машиной, на которой запущен браузер, и сервером. Список этих машин в принципе может быть разным для каждого запроса, поскольку одно изображение может перемещаться из США ко мне в Великобританию через Атлантику, а другое с того же сервера выходит через Тихий океан, Азию и Европу, что занимает больше времени. Таким образом, вы можете получить последовательность, подобную следующей, где страница имеет (в этом порядке) ссылки на три файла сценария и пять файлов изображений, все различающихся размеров:
- ПОЛУЧИТЬ script1 и script2; запрос очереди для script3 и images1-5.
- script2 прибывает (это меньше, чем script1): GET script3, очередь images1-5.
- script1 прибывает; ПОЛУЧИТЬ image1, очередь изображений2-5.
- image1 прибывает, ПОЛУЧИТЕ image2, очередь images3-5.
- script3 не может быть получен из-за проблем с сетью - GET script3 снова (автоматическая повторная попытка).
- image2 прибывает, script3 все еще не здесь; ПОЛУЧИТЬ image3, очередь изображений4-5.
- изображение 3 прибывает; ПОЛУЧИТЬ image4, очередь image5, script3 еще в пути.
- image4 прибывает, ПОЛУЧИТЕ image5;
- изображение5 прибывает.
- 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.