Изучите основы использования API навигации и синхронизации ресурсов для оценки производительности загрузки в реальных условиях.
Опубликовано: 8 октября 2021 г.
Если вы использовали ограничение скорости соединения в панели управления сетью в инструментах разработчика браузера (или Lighthouse в Chrome) для оценки производительности загрузки, вы знаете, насколько удобны эти инструменты для оптимизации производительности. Вы можете быстро измерить влияние оптимизации производительности при стабильной и постоянной базовой скорости соединения. Единственная проблема заключается в том, что это синтетическое тестирование, которое дает данные лабораторных условий , а не полевых .
Синтетическое тестирование само по себе не является чем-то плохим , но оно не отражает реальную скорость загрузки вашего сайта для реальных пользователей. Для этого необходимы данные из полей, которые можно получить с помощью API Navigation Timing и Resource Timing.
API-интерфейсы, которые помогут вам оценить производительность погрузки в полевых условиях.
API Navigation Timing и Resource Timing — это два похожих API, имеющих значительное совпадение, которые измеряют две разные вещи:
- Показатель Navigation Timing измеряет скорость запросов к HTML-документам (то есть, запросов навигации).
- Resource Timing измеряет скорость запросов к ресурсам, зависящим от документа, таким как CSS, JavaScript, изображения и другие типы ресурсов.
Эти API предоставляют свои данные в буфере записей производительности , к которому можно получить доступ в браузере с помощью JavaScript. Существует несколько способов запроса к буферу производительности, но наиболее распространенный — использование performance.getEntriesByType :
// Get Navigation Timing entries:
performance.getEntriesByType('navigation');
// Get Resource Timing entries:
performance.getEntriesByType('resource');
performance.getEntriesByType принимает строку, описывающую тип записей, которые вы хотите получить из буфера записей производительности. Методы 'navigation' и 'resource' получают данные о времени выполнения для API Navigation Timing и Resource Timing соответственно.
Объем информации, предоставляемой этими API, может быть огромным, но они являются вашим ключом к измерению производительности загрузки в реальных условиях, поскольку вы можете собирать эти данные от пользователей во время посещения вашего веб-сайта.
Время жизни и временные параметры сетевого запроса
Сбор и анализ данных о времени навигации и использования ресурсов чем-то сродни археологии: вы воссоздаёте мимолетную жизнь сетевого запроса постфактум. Иногда полезно визуализировать концепции, и в случае с сетевыми запросами могут помочь инструменты разработчика вашего браузера.

Жизненный цикл сетевого запроса состоит из различных фаз, таких как поиск DNS, установление соединения, согласование TLS и другие источники задержки. Эти временные параметры представлены в виде DOMHighResTimestamp . В зависимости от вашего браузера, точность измерения времени может составлять микросекунды или округляться до миллисекунд. Вам следует подробно изучить эти фазы и их связь с временем навигации и временем использования ресурсов.
поиск DNS
Когда пользователь переходит по URL-адресу, система доменных имен (DNS) запрашивается для преобразования домена в IP-адрес. Этот процесс может занять значительное время — время, которое вы захотите измерить в полевых условиях. Функции Navigation Timing и Resource Timing предоставляют два параметра, связанных с DNS:
-
domainLookupStartобозначает момент начала поиска DNS-запроса. -
domainLookupEnd— это момент завершения поиска DNS.
Общее время поиска DNS можно рассчитать, вычитая начальное значение из конечного значения:
// Measuring DNS lookup time
const [pageNav] = performance.getEntriesByType('navigation');
const totalLookupTime = pageNav.domainLookupEnd - pageNav.domainLookupStart;
согласование соединения
Ещё одним фактором, влияющим на производительность загрузки, является согласование соединения, то есть задержка, возникающая при подключении к веб-серверу. Если используется HTTPS, этот процесс также включает время согласования TLS. Фаза подключения состоит из трёх этапов:
-
connectStart— это событие, при котором браузер начинает устанавливать соединение с веб-сервером. - Параметр
secureConnectionStartуказывает момент начала согласования TLS-соединения клиентом. -
connectEndозначает, что соединение с веб-сервером установлено.
Измерение общего времени соединения аналогично измерению общего времени поиска DNS: вы вычитаете время начала из времени окончания. Однако существует дополнительное свойство secureConnectionStart , которое может быть равно 0 , если HTTPS не используется или если соединение является постоянным . Если вы хотите измерить время согласования TLS, вам нужно это учитывать:
// Quantifying total connection time
const [pageNav] = performance.getEntriesByType('navigation');
const connectionTime = pageNav.connectEnd - pageNav.connectStart;
let tlsTime = 0; // <-- Assume 0 to start with
// Was there TLS negotiation?
if (pageNav.secureConnectionStart > 0) {
// Awesome! Calculate it!
tlsTime = pageNav.connectEnd - pageNav.secureConnectionStart;
}
После завершения поиска DNS и согласования соединения вступают в действие временные параметры, связанные с получением документов и зависимых от них ресурсов.
Запросы и ответы
На эффективность нагружения влияют два типа факторов:
- Внешние факторы: это такие вещи, как задержка и пропускная способность. Помимо выбора хостинг-провайдера и, возможно, CDN , они (в основном) неподвластны нашему контролю, поскольку пользователи могут получить доступ к сети из любой точки мира.
- Внутренние факторы: это такие вещи, как архитектура сервера и клиента, а также размер ресурсов и наша способность оптимизировать их, которые находятся в пределах нашего контроля.
Оба типа факторов влияют на производительность загрузки. Показатели времени, связанные с этими факторами, имеют решающее значение, поскольку они описывают, сколько времени требуется для загрузки ресурсов. Показатели времени навигации и времени загрузки ресурсов описывают производительность загрузки с помощью следующих метрик:
- Параметр
fetchStartотмечает момент, когда браузер начинает загрузку ресурса (Resource Timing) или документа для запроса навигации (Navigation Timing). Это предшествует фактическому запросу и является точкой, в которой браузер проверяет кэш (например, экземпляры HTTP иCache). - Параметр
workerStartуказывает момент начала обработки запроса в обработчике событияfetchсервис-воркера. Значение будет равно0если ни один сервис-воркер не управляет текущей страницей. -
requestStart— это момент, когда браузер отправляет запрос. -
responseStart— это момент получения первого байта ответа. -
responseEnd— это момент получения последнего байта ответа.
Эти измерения позволяют оценить различные аспекты производительности загрузки, такие как поиск в кэше внутри сервис-воркера и время загрузки:
// Cache seek plus response time of the current document
const [pageNav] = performance.getEntriesByType('navigation');
const fetchTime = pageNav.responseEnd - pageNav.fetchStart;
// Service worker time plus response time
let workerTime = 0;
if (pageNav.workerStart > 0) {
workerTime = pageNav.responseEnd - pageNav.workerStart;
}
Вы также можете измерить другие аспекты задержки запроса и ответа:
const [pageNav] = performance.getEntriesByType('navigation');
// Request time only (excluding redirects, DNS, and connection/TLS time)
const requestTime = pageNav.responseStart - pageNav.requestStart;
// Response time only (download)
const responseTime = pageNav.responseEnd - pageNav.responseStart;
// Request + response time
const requestResponseTime = pageNav.responseEnd - pageNav.requestStart;
Другие измерения, которые вы можете произвести
Время навигации и время использования ресурсов полезны не только в тех случаях, которые описаны в предыдущих примерах. Вот еще несколько ситуаций с важными временными параметрами, которые стоит изучить:
- Перенаправления страниц: Перенаправления — это часто упускаемый из виду источник дополнительной задержки, особенно цепочки перенаправлений. Задержка возникает различными способами, например, при переходах HTTP-to-HTTPS, а также при перенаправлениях 302/некэшированных перенаправлениях 301. Показатели времени
redirectStart,redirectEndиredirectCountпомогают оценить задержку, возникающую при перенаправлении. - Выгрузка документа: На страницах, где код выполняется в обработчике события
unload, браузер должен выполнить этот код, прежде чем сможет перейти на следующую страницу.unloadEventStartиunloadEventEndизмеряют выгрузку документа. - Обработка документов: Время обработки документов может быть несущественным, если ваш веб-сайт не отправляет очень большие HTML-данные. Если это относится к вашей ситуации, вам могут быть полезны данные о времени выполнения событий
domInteractive,domContentLoadedEventStart,domContentLoadedEventEndиdomComplete.
Как получить данные о времени выполнения кода
Все приведенные до сих пор примеры используют performance.getEntriesByType , но существуют и другие способы запроса буфера записей производительности, такие как performance.getEntriesByName и performance.getEntries . Эти методы подходят, когда требуется лишь несложный анализ. Однако в других ситуациях они могут привести к чрезмерной нагрузке на основной поток из-за перебора большого количества записей или даже многократного опроса буфера производительности для поиска новых записей.
Рекомендуемый подход для сбора записей из буфера производительности — использование PerformanceObserver . PerformanceObserver отслеживает записи о производительности и предоставляет их по мере добавления в буфер:
// Create the performance observer:
const perfObserver = new PerformanceObserver((observedEntries) => {
// Get all resource entries collected so far:
const entries = observedEntries.getEntries();
// Iterate over entries:
for (let i = 0; i < entries.length; i++) {
// Do the work!
}
});
// Run the observer for Navigation Timing entries:
perfObserver.observe({
type: 'navigation',
buffered: true
});
// Run the observer for Resource Timing entries:
perfObserver.observe({
type: 'resource',
buffered: true
});
Этот метод сбора данных о времени выполнения может показаться неудобным по сравнению с прямым доступом к буферу записи производительности, но он предпочтительнее, чем загрузка основного потока работой, которая не служит критически важным и удобным для пользователя целям.
Как позвонить домой
После того, как вы соберете все необходимые данные о времени, вы можете отправить их на конечную точку для дальнейшего анализа. Это можно сделать двумя способами: с помощью navigator.sendBeacon или с помощью fetch с включенной опцией keepalive . Оба метода отправят запрос на указанную конечную точку в неблокирующем режиме, и запрос будет поставлен в очередь таким образом, чтобы при необходимости он сохранялся дольше текущей сессии страницы:
// Check for navigator.sendBeacon support:
if ('sendBeacon' in navigator) {
// Caution: If you have lots of performance entries, don't
// do this. This is an example for illustrative purposes.
const data = JSON.stringify(performance.getEntries());
// Send the data!
navigator.sendBeacon('/analytics', data);
}
В этом примере JSON-строка будет получена в виде POST -запроса, который вы сможете декодировать, обработать и сохранить в бэкэнде приложения по мере необходимости.
Заключение
После сбора метрик вам предстоит выяснить, как анализировать эти данные. При анализе данных следует придерживаться нескольких общих правил, чтобы делать обоснованные выводы:
- Избегайте использования средних значений , поскольку они не отражают опыт конкретного пользователя и могут быть искажены выбросами.
- Полагайтесь на процентили. В наборах данных, содержащих показатели производительности, зависящие от времени, чем ниже значение, тем лучше. Это означает, что, отдавая приоритет низким процентилям, вы обращаете внимание только на самые быстрые результаты.
- Отдавайте приоритет длинному хвосту ценностей . Когда вы отдаете приоритет опыту, находящемуся на 75-м процентиле или выше, вы сосредотачиваете внимание там, где ему и место: на самом медленном опыте.
Данное руководство не претендует на исчерпывающий характер по вопросам навигации или синхронизации ресурсов, а является лишь отправной точкой. Вот несколько дополнительных ресурсов, которые могут оказаться полезными:
- Технические характеристики синхронизации навигации .
- Спецификация временных параметров ресурсов .
- Использование ресурсов и времени на практике .
- API синхронизации навигации (MDN)
- API синхронизации ресурсов (MDN)
Благодаря этим API и предоставляемым ими данным вы сможете лучше понимать, как реальные пользователи воспринимают скорость загрузки, что позволит вам с большей уверенностью диагностировать и устранять проблемы со скоростью загрузки на практике.