Как модуль браузера Pre-loader ускоряет загрузку страниц.

Перевод статьи:  How the Browser Pre-loader Makes Pages Load Faster.
Автор:  Andy Davies.

Единственным когда-либо созданным средством улучшения производительности браузера можно с уверенностью назвать модуль pre-loader (так же известный как спекулятивный или опережающий pre-parser).

В ходе реализации этих компонентов корпорация Mozilla сообщила о показателе 19% уменьшения времени загрузки, а Google в результатах своего тестирования на основе 2000 сайтов, входящих в "Alexa top" заявил о 20% улучшений.

Данная функциональность браузеров не является новой, однако многим кажется, что она свойственна исключительно Chrome, в то время как другие считают ее самым деструктивным «улучшением производительности», когда-либо имевшим место.

Что ж, давайте узнаем, что такое pre-loader и как именно он улучшает производительность браузера.

Как обычно происходит процесс загрузки веб-страницы браузером.

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

Давайте пошагово рассмотрим возможные действия браузера при загрузке страницы:

  • Прежде всего, загружается исходный HTML код, и движок браузера приступает к его парсингу, в ходе которого находятся ссылки на внешние CSS ресурсы и инициируются соответствующие сетевые запросы на их загрузку.
  • Браузер допускает продолжение процесса парсинга во время загрузки стилевых данных, однако после обнаружения тега script, содержащего внешний URL, парсер вынужден будет ожидать загрузки этого скрипта и последующего его выполнения (кроме тех случаев, когда скрипт обладает атрибутом async или defer).
  • Сразу же после загрузки и выполнения данного скрипта браузер сможет продолжить анализ исходного HTML кода. Когда он встречает не блокирующие процесс парсинга ресурсы, подобные изображениям, он выполнит запрос на их загрузку и без промедления продолжает анализ документа, но если это будет скрипт, то парсинг приостанавливается до момента окончания его выполнения с предварительной загрузкой при необходимости.

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

Именно так ведут себя браузеры в описанных ситуациях. С помощью предоставленного Стивом Саундерсом сервиса Curzillion мы можем создать тестовую страницу, демонстрирующую описанные выше обстоятельства в IE7.

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

Благодаря представленному ниже нисходящему графику можно увидеть, что в ходе загрузки скрипта режим параллельных загрузок отключается.

Ниспадающий график параллельных загрузок браузера IE7.

«Водопад», образуемый сгенерированной с помощью Cuzillion тестовой страницей в IE7.

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

Как благодаря модулю pre-loader повышается эффективность использования сетевых ресурсов.

Все производители, еще в 2008 году включившие в состав своих продуктов функционал pre-loader — Internet Explorer, WebKit и Mozilla сделали это с целью решения проблем, связанных с максимальным использованием возможностей низкоскоростного сетевого соединения в период ожидания загрузки скриптов и их выполнения.

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

После этого модуль pre-loader начинает извлечение обнаруженных ресурсов в фоновом режиме. Таким образом, при достижении основным HTML парсером браузера элементов, ссылающихся на эти ресурсы, они вероятнее всего уже будут загружены и готовы к использованию. А это в свою очередь позволит избежать блокировок процесса обработки страницы в дальнейшем.

Если же определенный ресурс уже находится в кэше браузера, то, само собой разумеется, в его повторной загрузке нет необходимости.

И теперь, если мы повторно выполним предыдущий тест с использованием IE8, то обнаружим, что другие, связанные с документом ресурсы загружаются параллельно с процессом обработки скриптов. Это дает огромное преимущество в производительности данного теста. Чувствуете разницу 7 секунд и 14?

Ниспадающий график параллельных загрузок браузера IE8.

«Водопад», образуемый сгенерированной с помощью Cuzillion тестовой страницей в IE8.

В каждом предусматривающем наличие pre-loader браузере поведение этого модуля несколько отличается. Он представляет собой широкую область для экспериментов. Некоторые браузеры реализуют довольно простой вариант данного функционала, при котором ресурсы загружаются последовательно в соответствии с порядком их обнаружения в документе. Другие же устанавливают приоритеты для загрузок определенных ресурсов. Так, к примеру, в Safari таблицы стилей, не отвечающие текущим размерам вьюпорта, получают низкий приоритет, а Chrome распределяет загрузку таким образом, что скрипты получают более высокий приоритет (даже те, которые находятся в конце документа), чем большинство изображений.

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

Глюки модуля Pre-Loader.

Pre-loader извлекает URL адреса из разметки, но он не выполняет (просто не в состоянии выполнять) скрипты, поэтому те URL, которые появляются в результате работы JavaScript, данному модулю не доступны. Из этого следует, что загрузка соответствующих ресурсов будет отложена до того, как основной HTML парсер обнаружит и выполнит загружающие их скрипты.

В некоторых случаях вставка в документ ресурсов посредством JavaScript может сбить с толку сканер предварительной загрузки.

На ресурсе Stack Overflow я столкнулся с одной из рекомендаций использования JavaScript для вставки ссылки на необходимую таблицу стилей, которая выбирается на основе ширины окна браузера целевого устройства:

<html>
<head>
<script>
var file = window.innerWidth < 1000 ? "mobile.css" : "desktop.css";
document.write('<link rel="stylesheet" type="text/css" href="css/' + file + '"/>');
</script>
</head>
<body>
<img src="img/gallery-img1.jpg" />
<img src="img/gallery-img2.jpg" />
<img src="img/gallery-img3.jpg" />
<img src="img/gallery-img4.jpg" />
<img src="img/gallery-img5.jpg" />
<img src="img/gallery-img6.jpg" />
</body>
</html>

Я бы не воспользовался таким способом подключения необходимых ресурсов по нескольким причинам. Но даже такого простейшего примера достаточно чтобы увидеть, что модуль pre-loader браузера IE9 может столкнутся с трудностями при таком подходе. Обратите внимание, как под загрузку изображений выделяются все доступные соединения, а доставка CSS файла откладывается до окончания загрузки одного из изображений, после чего освободившееся сетевое соединение предоставляется под загрузку таблицы стилей.

Тест загрузки страницы в IE9.

Тест загрузки страницы в IE9.

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

Способы влияния на работу модуля pre-loader.

На сегодняшний день количество методов воздействия на приоритеты сканера предварительной загрузки весьма ограничено (одним из которых является «скрытие» ресурсов с помощью JavaScript). Однако, W3C спецификацией «Приоритеты ресурсов» вводятся два атрибута, позволяющие авторам обозначить собственные намерения.

lazyload:
ресурс не должен загружаться до начала загрузки других ресурсов, которые не помечены как "lazyload" (*«Загрузка по требованию» или «ленивая загрузка» — ресурс не загружается до тех пор, пока в нем нет необходимости, хотя его адрес известен).
postpone:
ресурс не должен загружаться до тех пор, пока он не будет виден пользователю, т.е. находиться в области видимости вьюпорта и значение его свойства display будет отлично от none (*"Postpone loading" — отложенная загрузка).

Затрудняюсь сказать насколько реально использование полифилла в данном случае. Вероятно, что с помощью атрибута postpone можно создать несложный способ реализации отзывчивых изображений.

Pre-loading против Pre-fetching.

Pre-fetching представляет собой способ предоставления браузеру подсказок касательно ресурсов, которые неизбежно или вероятно будут использоваться в дальнейшем при отображении документа. Некоторые из этих подсказок относятся к текущей странице, другие же к тем страницам, которые возможно будут востребованы пользователем в дальнейшем.

В качестве одного из простейших вариантов таких подсказок можно назвать указание браузеру разрешить DNS имя хоста, к которому планируется обращение в процессе отображения страницы в будущем:

<link rel="dns-prefetch" href="other.hostname.com">

Chrome также позволяет нам указать на то, что в дальнейшем при обработке текущей страницы может понадобиться другой ресурс, загрузка которого должна производиться с высоким приоритетом:

<link rel="subresource" href="/some_other_resource.js">

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

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

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

<link rel="prefetch" href="/some_other_resource.jpeg">

Предварительная загрузка и визуализация целой страницы на фоновой вкладке:

<link rel="prerender" href="//domain.com/next_page.html">

В качестве отличной стартовой точки для более глубокого изучения преимуществ использования средств предварительной выборки ресурсов можно порекомендовать представленную Ильей Григориком на конференции WebPerfDays в Нью Йорке презентацию «Предварительная выборка, визуализация, установление соединения…».

Выводы.

Модуль pre-loader не является чем-то абсолютно новым, обеспечивает значительный подъем производительности, а нам, как авторам документов и приложений не нужно делать что-либо для того чтобы им воспользоваться.

Он широко распространен и чтобы это подтвердить, я лично провел некоторые исследования, в результате которых обнаружил, что pre-loader используется в:

  • IE8 / 9 /10
  • Firefox
  • Chrome (включая Android)
  • Safari (включая iOS)
  • Android 2.3

В дополнение к этому, Брюс Лоусон подтвердил то, что в используемом в Opera Mini движке Presto так же предусмотрен модуль pre-loader.

Представляемые W3C спецификацией «Приоритеты ресурсов» (и, возможно, атрибутом <link rel=subresource…) возможности, позволят нам сообщать данному модулю собственные приоритеты.

Использованная литература и рекомендованное чтение:

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

Сканер предварительной загрузки движка Webkit.

Процесс загрузки веб-страницы.

Спекулятивная загрузка файлов сопроводительных ресурсов в ходе блокировки «реального» парсинга при загрузке скриптов.

Реализация спекулятивной предварительной загрузки.

Лучшая практика: Упорядочивание содержимого элемента HEAD.

Баги IE8 — Упреждающий загрузчик.

W3C — «Приоритеты ресурсов».

Chrome PLT улучшения Q1 3013.

Предварительная выборка, визуализация, установление соединения…

* Примечание переводчика.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *