Что делает сайты медленнее?

Аналитики CatchJS отрендерили 1 миллион самых популярных сайтов. Они отследили разнообразные метрики производительности, учли каждую ошибку и отметили каждый запрошенный URL. Результат составляет, вероятно, первый набор данных, связывающий производительность, ошибки и использование библиотек. В этой статье мы проанализируем, что могут рассказать эти данные о создании высокопроизводительных сайтов.

Набор данных можно найти в Kaggle.

Зачем рендерить миллион веб-страниц?

Сейчас распространено мнение, что интернет каким-то образом стал медленнее и содержит больше ошибок, чем 15 лет назад. Благодаря постоянно растущим возможностям JavaScript, а также различным фреймворкам, шрифтам и полифиллам, разработчики нивелировали все те преимущества, которые были даны более мощными компьютерами, сетями и протоколами. По крайней мере, так утверждается. Аналитики CatchJS хотели узнать, правда ли это, и попытались выяснить, какие общие факторы делают сайты медленными и кривыми.

Основной план был таков: написать скрипт для браузера, который будет рендерить основную страницу каждого из миллиона сайтов. Затем он запишет всевозможные метрики: время рендеринга, количество запросов, ошибки из JavaScript, использованные библиотеки и так далее. Имея все эти данные, можно узнать, как один фактор коррелирует с другим. Какие из них в наибольшей степени способствуют замедлению времени рендеринга? Какие библиотеки замедляют ожидание перед загрузкой сайта? Каковы наиболее распространенные ошибки и что их вызывает?

Сбор данных состоял в том, чтобы написать небольшую программу для Puppeteer, который поможет сделать скрипт для Chrome. Затем запустить 200 экземпляров EC2 и отрисовать миллион веб-страниц.

Общие цифры

Использование протокола для корневого HTML-файла

HTTP/2 сейчас используется чаще, чем HTTP/1.1. Однако HTTP/3 по-прежнему редкость. Примечание: в исследовании учитывалось все, что использует протокол QUIC, такой как HTTP/3, даже если Chrome иногда отмечает это как сочетание HTTP/2 + QUIC. Однако эти данные касаются лишь основной страницы, а для связанных ресурсов все обстоит немного иначе.

Использование протокола для связанных ресурсов

В них HTTP/3 распространен примерно в 100 раз больше. Как это возможно? Это происходит потому, что все сайты ссылаются на одни и те же источники.

Самые популярные связанные ресурсы

Вот список тех файлов, на которые ссылается большинство сайтов. Значит ли это, что можно полагать, будто эти ресурсы будут в кэше? Как бы не так: начиная с 86 версии Chrome, ресурсы, запрошенные с разных доменов, не будут совместно использовать кэш. В Firefox планируется ввести подобное. А Safari уже много лет не совмещает кэш для разных сайтов.

Что замедляет интернет: прогнозирование времени до полной загрузки сайта

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

Корреляция метрик с domInteractive

На деле все метрики связаны с domInteractive, кроме одной переменной, которая указывает, используется ли на сайте HTTP/2 или выше. Многие из этих метрик также хорошо соотносятся друг с другом. Чтобы разобраться в отдельных факторах, влияющих на более долгую загрузку, нужен более изощренный подход.

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

Оранжевой линией выделена медиана, а рамки указаны от 25-го до 75-го процентиля

Один из способов получить представление об отдельных факторах, способствующих высокому времени загрузки,  —  создание линейной регрессии, в которой можно спрогнозировать доминирующую активность по другим показателям. Это означает, что нужно присвоить вес каждой метрике и смоделировать время действия страницы как взвешенную сумму других метрик + некую константу. Алгоритм оптимизации устанавливает веса таким образом, чтобы минимизировать ошибку прогнозирования по всему набору данных. Размер весов, найденных с помощью линейной регрессии, показывает, насколько каждая метрика влияет на скорость загрузки страницы.

Однако в рамках эксперимента временные метрики были исключены из регрессии. Если бы на установку соединения было потрачено 500 мс, то это бы добавило еще 500 мс к domInteractive. Но это не самое главное. Временные метрики в основном являются показателями результата, а здесь нужно узнать, что же их вызывает.

Коэффициенты регрессии, рассчитывающие domInteractive

Числа в скобках  —  это коэффициенты регрессии, полученные с помощью алгоритма оптимизации. Их можно интерпретировать как единицы измерения в мс. И хотя точным цифрам не стоит верить на все 100% (ниже этому есть объяснение), все же интересно увидеть вклад каждого из параметров измерения.

К примеру, модель высчитывает замедление в 354 мс за каждую переадресацию, необходимую для загрузки основной страницы. Каждый раз, когда основной HTML-файл страницы загружается по HTTP/2 или выше, модель выдает увеличение времени на 477 мс до полной загрузки страницы. По каждому запросу, вызванному этим файлом, модель добавляет ко времени загрузки еще по 16 мс.

При интерпретации коэффициентов регрессии следует иметь в виду, что расчеты выполняются по упрощенной модели. Время полной загрузки страницы на самом деле не определяется взвешенной суммой этих входных метрик. Очевидно, существуют причины, которые данная модель не в силах распознать.

Искажающие факторы, безусловно, являются проблемой. Например, если загрузка основной страницы с помощью HTTP/2 коррелирует с загрузкой других запросов через этот же протокол, то модель примет это преимущество в весах для main_doc_is_http2_or_greater, даже если ускорение загрузки происходит от запросов, отличных от данных основной страницы.

Как версия протокола HTTP влияет на domInteractive?

Рассмотрим такую ситуацию, где domInteractive работает на разных версиях HTTP-протокола для запуска основной страницы сайта.

Вот график, показывающий разделение domInteractive на различные версии протокола первого запроса. Оранжевой линией выделена медиана, а рамки указаны от 25-го до 75-го процентилей. Проценты в скобках указывают на доли запросов, выполненных с помощью каждой из версий протокола.

Как видно из графика, осталось лишь небольшое количество сайтов, до сих пор использующих HTTP/0.9 и HTTP/1.0. И эти сайты, на удивление, быстро загружаются. Кажется, нельзя отрицать и тот факт, что по мере ускорения протоколов программисты также с радостью начали нагружать сайты, чтобы выдать как можно больше данных.

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

Коэффициенты регрессии для количества запросов по версии протокола, рассчитанные по domInteractive

Если верить графику, то можно прийти к выводу, что “переезд” с протокола HTTP/1.1 на HTTP/2 дает прирост к скорости в 1.8 раза. В то же время переход со второй на третью версию протокола замедляет загрузку сайта в 0.6 раз. Значит ли это, что HTTP/3  —  более медленный? Нет, это не так.

Более вероятным объяснением можно считать то, что HTTP/3 еще не так часто используется, и те немногочисленные ресурсы, отправляемые по HTTP/3 (например, Google Analytics), оказывают большее влияние на domInteractive.

Как тип контента влияет на domInteractive?

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

Коэффициенты регрессии для количества килобайтов, поделенных по типу данных, рассчитанные для domInteractive

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

Коэффициенты регрессии для количества запросов от инициатора запроса, рассчитанные по domInteractive

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

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

Выводы

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

  • Делайте как можно меньше запросов. Число запросов влияет на скорость загрузки больше, чем количество переданных килобайтов.
  • Для тех запросов, которые все-таки нужно выполнить, используйте протокол HTTP/2 или выше.
  • Старайтесь избегать запросов с блокировкой рендеринга, желательно использование асинхронной загрузки сайта.

Библиотеки

Чтобы определить, какие библиотеки были использованы на сайтах, использовался такой подход: на каждом сайте отмечалось наличие глобальных переменных (например, свойства объекта окна). После этого каждая глобальная переменная (их число колеблется около 6 тысяч) связывалась с подходящей ей JavaScript-библиотекой. Это кропотливая работа, но поскольку в наборе данных также есть запрашиваемые URL-адреса для каждой страницы, аналитики смогли посмотреть на совпадение между встречаемостью переменных и запросами URL-адресов. Этого часто было достаточно, чтобы определить библиотеки, устанавливающие глобальные переменные.

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

Какие JavaScript-библиотеки сейчас используются больше всего? Судя по темам конференций и постам в блогах можно предположить, что это React, Vue и Angular. Однако в данном списке они стоят далеко не вверху.

10 самых популярных библиотек

Да, старый-добрый jQuery находится на вершине списка. jQuery был выпущен в 2006 году, то есть 16 лет назад, что намного больше по меркам живучести JS-библиотек. Если считать по количеству версий Angular, то это было сотни версий назад.

В 2006 году все было совершенно по-другому. Самым популярным браузером был Internet Explorer 6, самой большой соцсетью  —  MySpace, а закругленные углы веб-страниц  —  настоящей революцией, из-за чего такое явление прозвали web 2.0. JQuery в основном использовали из-за кросс-браузерной совместимости, однако и это явление теперь является совершенно не таким, как в то время. Но даже 16 лет спустя целая половина сайтов из данной подборки подгружает jQuery.

Интересный факт: 2,2% сайтов выдали ошибку, потому что в них не загрузился jQuery.

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

Прогнозирование времени загрузки в соответствии с использованием библиотек

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

  • X[i] = 1.0, если библиотека i присутствует;
  • X[i] = 0.0, если отсутствует.

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

Лучшие и худшие библиотеки по времени загрузки страницы с учетом коэффициента регрессии

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

Результаты можно рассматривать как технической, так и с социологической стороны. Например, библиотеки с использованием “ленивой загрузки” показывают малое время до полной отрисовки контента. Это может быть связано с тем, что страницы с этими библиотеками сделаны программистами, которые потратили время на оптимизацию быстрой загрузки страниц наравне с ленивой загрузкой. Однако установить истинные причины такого поведения сайтов на основе данной методологии невозможно.

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

Предыдущие замеры можно повторить и с расчетом отложенного времени загрузки. Время отложенной загрузки (onloadtime)  —  это время, которое требуется для запуска события “load”, означающего полную прогрузку всех ресурсов страницы. В этом примере также использовалась линейная регрессия.

Лучшие и худшие библиотеки в плане использования jsheapusedsize с учетом коэффициентов регрессии

А вот расчет размера кэша, используемого JavaScript, в мегабайтах.

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

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

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Lars Eidnes: We rendered a million web pages to find out what makes the web slow

Предыдущая статьяPython для начинающих: какая разница между tuple, list и set?
Следующая статья20 скрытых особенностей JavaScript