Послідовність завантаження та виконання веб-сторінки?


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. Коли $ (документ). Вже виконується?
  6. Чи буде завантажено abc.jpg? Або просто завантажується kkk.png?

Я розумію таке:

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

Або це так:

Браузер аналізує html (DOM) і отримує зовнішні ресурси в масиві або схожій на стек структурі. Після завантаження html браузер починає паралельно завантажувати зовнішні ресурси в структуру і виконувати, поки всі ресурси не завантажуються. Тоді DOM буде змінено відповідно до поведінки користувача залежно від JS.

Хто-небудь може дати детальне пояснення того, що відбувається, коли ви отримаєте відповідь на html-сторінці? Чи відрізняється це в різних браузерах? Будь-яка посилання на це питання?

Дякую.

Редагувати:

Я зробив експеримент у Firefox з Firebug. Він відображається у вигляді наступного зображення: alt текст


11
Стів Суудерс провів велику роботу в цій галузі. Google for steve + souders + high + performance та ознайомтесь.
anddoutoi

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

2
Читаючи його роботу, моє розуміння того, як "це" працює докладно, збільшилося вдесятеро, тому це все-таки вагомий коментар. Авторські права мені не дозволяють цитувати всю цю книгу, тому я все-таки пропоную переглянути його твір.
anddoutoi

3
Чудовий опис замовлення, що відбувається, є тут
Геррат

Відповіді:


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: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 лише після його розбору. Таким чином, при роботі з певним елементом сценарій завжди розміщується після події завантаження вікна або всередині нього.

Такий сценарій спричинить помилку (на 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
Дякую. Але ви згадали, що завантаження може бути асинхронним і не блокуючим через поведінку браузера , тому які компоненти можна завантажити в asyn (візьміть FF як екземпляр)? <script>заблокує інші компоненти, правда? Будь-яка посилання на специфікацію для кожного браузера?
Чжу Тао

4
$ (document) .ready () запускається, коли DOM заповнений, а не коли всі компоненти сторінки завантажені
Pierre

2
@Pierre за компонентами сторінки Я мав на увазі DOM -> будь-які компоненти в DOM.
mauris

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

1
Якщо на вкладці <body> ми додамо <link href = "bootstrap.min.css" rel = "таблиця стилів" /> між <img> та <script> тегом, ніж img, не відображається, поки завантажений завантажувальний конт ... тому я думаю, що крок [13], [14] потребує модифікації ... може хтось пояснить таку поведінку?
Буван

34

1) HTML завантажується.

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

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

4) Лише після того, як DOM буде повністю виведений і запити на всі активи на сторінці вирішені, або час вичерпання виконує JavaScript від події завантаження. IE7, і я не впевнений у IE8, не швидко виправляє активи, якщо відповідь HTTP не буде отримана з запиту активу. Це означає, що ресурс, запитуваний JavaScript на вказівці на сторінку, тобто JavaScript, записаний у теги HTML, який не міститься у функції, може запобігти виконанню події завантаження протягом годин. Цю проблему можна викликати, якщо такий вбудований код існує на сторінці та не виконається через зіткнення простору імен, що спричиняє збій коду.

З вищезазначених етапів, найбільш інтенсивним процесором є аналіз DOM / CSS. Якщо ви хочете, щоб ваша сторінка була швидше оброблена, тоді пишіть ефективний CSS, усуваючи зайві інструкції та консолідуючи інструкції CSS у найменші посилання на елементи. Зменшення кількості вузлів у вашому дереві DOM також призведе до швидшого відображення.

Майте на увазі, що кожен актив, який ви запитуєте від свого HTML або навіть від ваших активів CSS / JavaScript, запитується окремим заголовком HTTP. Це споживає пропускну здатність і вимагає обробки за запитом. Якщо ви хочете, щоб ваша сторінка завантажувалася якомога швидше, тоді зменшіть кількість запитів HTTP та зменшіть розмір вашого HTML. Ви не робите користувачеві жодних прихильностей, усереднюючи вагу сторінки в 180k лише від HTML. Багато розробників підписуються на помилку, що користувач вирішує питання про якість вмісту на сторінці за 6 наносекунд, а потім очищує DNS-запит зі свого сервера і спалює комп'ютер, якщо він не задоволений, тому натомість вони надають найкрасивішу можливу сторінку на 250k HTML. Нехай ваш HTML короткий і солодкий, щоб користувач міг швидше завантажувати ваші сторінки.


2
консолідація інструкцій CSS в найменші посилання на елементи Звучить дивно. Якщо мені потрібно стилізувати три елементи, мені потрібно посилатись саме на три елементи. Я не можу віднести одного до стилю десять, чи не так? Або детальніше про це
Зелений

12

Відкрийте сторінку у Firefox та отримайте додаток HTTPFox. Це підкаже вам все, що вам потрібно.

Знайдено це на archivist.incuito:

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

Під час першого запиту на сторінку ваш браузер надсилає GET-запит на сервер, який повертає HTML-браузер. Потім браузер починає розбирати сторінку (можливо, до того, як вона буде повернута).

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

Однак стандарт HTTP визначає, що браузер не повинен робити більше двох одночасних запитів до одного домену. Таким чином, він ставить кожен запит до певного домену в черзі, і коли кожне об'єднання повернене, воно запускає наступний у черзі для цього домену.

Час, необхідний для повернення об'єкта, залежить від його розміру, навантаження, яку зараз переживає сервер, та активності кожної машини між машиною, що працює під браузером та сервером. Перелік цих машин в принципі може бути різним для кожного запиту, наскільки одне зображення може подорожувати зі США до мене у Великобританії через Атлантику, а інше з того ж сервера виходить через Тихий, Азію та Європу, що займає більше часу. Таким чином, ви можете отримати послідовність на зразок наступної, де на сторінці є (в такому порядку) посилання на три файли сценаріїв і п'ять файлів зображень, всі різного розміру:

  1. GET script1 та script2; запит черги на script3 та images1-5.
  2. скрипт2 надходить (він менший, ніж скрипт1): GET script3, зображення черги1-5.
  3. сценарій1 прибуває; Отримайте image1, зображення черги2-5.
  4. image1 надходить, GET image2, queue images3-5.
  5. сценарій не надходить через мережеву проблему - знову GET script3 (автоматична спроба).
  6. image2 прибуває, script3 досі тут не знаходиться; Отримати зображення3, черги - зображення4-5.
  7. зображення 3 надходить; Отримати image4, чергу черги5, script3 ще на шляху.
  8. image4 прибуває, GET image5;
  9. image5 прибуває.
  10. сценарій3 прибуває.

Коротше кажучи: будь-який старий порядок, залежно від того, що робить сервер, що робить інша частина Інтернету та чи має щось помилки, і їх потрібно повторно вибирати. Це може здатися дивним способом ведення справ, але це було б буквально неможливо, щоб Інтернет (не лише WWW) працював з будь-яким ступенем надійності, якби це не було зроблено таким чином.

Крім того, внутрішня черга веб-переглядача може не отримувати об'єкти в тому порядку, який вони відображаються на сторінці - це не вимагає жоден стандарт.

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



2

AFAIK, браузер (принаймні Firefox) запитує кожен ресурс, як тільки він його розбирає. Якщо він зустріне тег img, він запитає це зображення, як тільки тег img буде розібраний. І це може бути навіть до того, як він отримає сукупність HTML-документа ... тобто це все ще може завантажувати HTML-документ, коли це станеться.

Для Firefox існують черги браузера, які застосовуються, залежно від того, як вони встановлені в about: config. Наприклад, він не намагатиметься завантажити більше 8 файлів одночасно з того самого сервера ... додаткові запити будуть поставлені в чергу. Я думаю, що існують обмеження по домену, обмеження проксі-сервера та інші речі, які задокументовані на веб-сайті Mozilla і можуть бути встановлені приблизно в: 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.