В этом руководстве объясняется, как использовать Performance API для записи статистики, подобной DevTool, от реальных пользователей, обращающихся к вашему приложению.
Оценка производительности
Введение в API производительности
API производительности использует буфер для записи метрик, подобных DevTool, в свойствах объекта в определенные моменты жизни вашей
Навигация по страницам: записывайте перенаправления при загрузке страницы, подключения, рукопожатия, события DOM и многое другое.
Загрузка ресурсов: записывайте загрузку ресурсов, таких как изображения, CSS, скрипты и вызовы Ajax.
Показатели Paint: запись информации о рендеринге в браузере.
Пользовательская производительность: записывайте произвольное время обработки приложения, чтобы найти медленные функции.
Все API доступны в клиентском JavaScript, включая Web Workers. Вы можете обнаружить поддержку API, используя:
if ('performance’ in window) {
// call Performance APIs
}
Примечание. Имейте в виду, что Safari поддерживает не все методы, несмотря на реализацию большей части API.
Пользовательские (пользовательские) API производительности также реплицируются в:
встроенный performance_hookмодуль Node.js и
API производительности Deno (скрипты, использующие его, должны запускаться с —
Разве недостаточно Date () хорошо?
Возможно, вы видели примеры использования этой Date () функции для записи прошедшего времени. Например:
const start = new Date () ;
//... run code...
const elapsed = new Date () — start;
Однако Date () расчеты ограничены ближайшей миллисекундой и основаны на системном времени, которое ОС может обновить в любой момент.
Performance API использует отдельный таймер с более высоким разрешением, который может записывать доли миллисекунды. Он также предлагает метрики, которые было бы невозможно записать иначе, например, время перенаправления и поиска DNS.
Запись показателей производительности
Вычисление метрик производительности в коде на стороне клиента полезно, если вы можете записать его
В качестве альтернативы, большинство аналитических систем предлагают настраиваемые
const pageload = performance.getEntriesByType ('navigation’)[0];
ga ('send’, 'timing’, 'pageload’, 'DOMready’, pageload.domContentLoadedEventStart) ;
В этом примере используется API времени навигации по страницам. так что начнем там...
Время навигации по странице
Тестирование вашего сайта на быстром соединении вряд ли будет свидетельствовать о пользовательском опыте. Вкладка браузера DevTools Network позволяет регулировать скорость, но не может эмулировать слабые или прерывистые сигналы 3G.
API синхронизации навигации помещает один PerformanceNavigationTimingобъект в буфер производительности. Он содержит информацию о редиректах, времени загрузки, размерах файлов, событиях DOM и так далее, наблюдаемых реальным пользователем.
Получите доступ к объекту, выполнив:
const pagePerf = performance.getEntriesByType ('navigation’) ;
Или получить к нему доступ, передав
const pagePerf = performance.getEntriesByName (window.location) ;
Оба возвращают массив с одним элементом, содержащим объект со свойствами только для чтения. Например:
[
{
name: «https: //site.com/»,
initiatorType: «navigation»,
entryType: «navigation»,
initiatorType: «navigation»,
type: «navigate»,
nextHopProtocol: «h2»,
startTime: 0
...
}
]
Объект включает в себя свойства идентификации ресурса:
имущество описание
имя
тип записи тип производительности — «navigation»для страницы, «resource»для актива
тип инициатора ресурс, инициировавший загрузку — «navigation»для страницы
nextHopProtocol сетевой протокол
serverTiming массив объектов PerformanceServerTiming
Примечание. PerformanceServerTiming name, description, и durationметрики записываются в
Объект включает свойства времени ресурса в миллисекундах относительно начала загрузки страницы. Времена обычно ожидаются в таком порядке:
имущество описание
время начала отметка времени начала выборки — 0для страницы
рабочийстарт метка времени перед запуском Service Worker
перенаправлениеСтарт метка времени первого перенаправления
redirectEnd метка времени после получения последнего байта последнего перенаправления
fetchStart метка времени перед получением ресурса
доменLookupStart метка времени перед поиском DNS
доменLookupEnd отметка времени после поиска DNS
connectStart метка времени перед установлением соединения с сервером
connectEnd отметка времени после установления соединения с сервером
SecureConnectionStart метка времени перед рукопожатием SSL
запросСтарт метка времени перед запросом браузера
ответСтарт метка времени, когда браузер получает первый байт данных
ответКонец метка времени после получения последнего байта данных
продолжительность время, прошедшее между startTime и responseEnd
Объект включает свойства размера загрузки в байтах:
имущество описание
размер передачи размер ресурса, включая заголовок и тело
encodedBodySize размер тела ресурса перед распаковкой
decodedBodySize размер тела ресурса после распаковки
Наконец, объект включает дополнительную навигацию и свойства события DOM (недоступно в Safari):
имущество описание
тип либо «navigate», либо «reload„_“back_forward»»prerender»
redirectCount количество редиректов
unloadEventStart метка времени перед unloadсобытием предыдущего документа
unloadEventEnd метка времени после unloadсобытия предыдущего документа
ДомИнтерактив метка времени, когда парсинг HTML и построение DOM завершены
domContentLoadedEventStart метка времени перед запуском DOMContentLoadedобработчиков событий
domContentLoadedEventEnd метка времени после запуска DOMContentLoadedобработчиков событий
domComplete метка времени, когда построение DOM и DOMContentLoadedсобытия завершены
loadEventStart метка времени перед запуском loadсобытия страницы
loadEventEnd loadметка времени после события страницы. Все ресурсы загружены
Пример записи показателей загрузки страницы после ее полной загрузки:
'performance’ in window && window.addEventListener ('load’, () => {
const
pagePerf = performance.getEntriesByName (window.location)[0],
pageDownload = pagePerf.duration,
pageDomComplete = pagePerf.domComplete;
}) ;
Время ресурса страницы
API Resource Timing помещает PerformanceResourceTimingобъект в буфер производительности всякий раз, когда ресурс, такой как изображение, шрифт, файл CSS, файл JavaScript или любой другой элемент, загружается страницей. Бегать:
const resPerf = performance.getEntriesByType ('resource’) ;
Это возвращает массив объектов синхронизации ресурсов. Они имеют те же свойства, что и время страницы, показанное выше, но без навигации и информации о событиях DOM.
Вот пример результата:
[
{
name: «https: //site.com/style.css»,
entryType: «resource»,
initiatorType: «link»,
fetchStart: 150,
duration: 300
...
},
{
name: «https: //site.com/script.js»,
entryType: «resource»,
initiatorType: «script»,
fetchStart: 302,
duration: 112
...
},
...
]
Один ресурс можно проверить, передав его URL.getEntriesByName () методу:
const resourceTime = performance.getEntriesByName ('https: //site.com/style.css’) ;
Это возвращает массив с одним элементом:
[
{
name: «https: //site.com/style.css»,
entryType: «resource»,
initiatorType: «link»,
fetchStart: 150,
duration: 300
...
}
]
Вы можете использовать API, чтобы сообщать о времени загрузки и размере каждого файла CSS в распакованном виде:
// array of CSS files, load times, and file sizes
const css = performance.getEntriesByType ('resource’)
.filter (r => r.initiatorType === 'link’ && r.name.includes ('.css’))
.map (r => ({
name: r.name,
load: r.duration + 'ms’,
size: r.decodedBodySize + ' bytes’
}));
Массив cssтеперь содержит объект для каждого файла CSS. Например:
[
{
name: «https: //site.com/main.css»,
load: «155ms»,
size: «14304 bytes»
},
{
name: «https: //site.com/grid.css»,
load: «203ms»,
size: «5696 bytes»
}
]
Примечание: загрузка и размер, равные нулю, указывают на то, что актив уже был кэширован.
В буфер производительности будет записано не менее 150 объектов метрик ресурсов. Вы можете определить конкретное число с помощью.setResourceTimingBufferSize (N) метода. Например:
// record 500 resources
performance.setResourceTimingBufferSize (500) ;
Существующие показатели можно очистить с помощью команды.clearResourceTimings () method.
Время отрисовки браузера
First Contentful Paint (FCP) измеряет, сколько времени требуется для отображения контента после того, как пользователь перейдет на вашу страницу. В разделе «Производительность «панели Chrome DevTool Lighthouse показана метрика. Google считает, что время FCP менее двух секунд является хорошим, и ваша страница будет отображаться быстрее, чем 75% Интернета.
Paint Timing API отправляет две записи двух объектов PerformancePaintTiming в буфер производительности, когда:
происходит первая краска: браузер рисует первый пиксель, и
происходит
Оба объекта возвращаются в массиве при запуске:
const paintPerf = performance.getEntriesByType ('paint’) ;
Пример результата:
[
{
«name»: «
«entryType»: «paint»,
«startTime»: 125
},
{
«name»: «
«entryType»: «paint»,
«startTime»: 127
}
]
startTime относится к начальной загрузке страницы.
Время пользователя
API производительности можно использовать для определения времени работы ваших собственных приложений. Все пользовательские методы измерения времени доступны в клиентском JavaScript, Web Workers, Deno и Node.js.
Обратите внимание, что сценарии Node.js должны загружать модуль Performance hooks (perf_hooks).
requireСинтаксис CommonJS:
const { performance } = require ('perf_hooks’) ;
importИли синтаксис модуля ES:
import { performance } from 'perf_hooks’;
Самый простой вариант — performance.now (), который возвращает отметку времени с высоким разрешением с начала жизни процесса.
Вы можете использовать performance.now () для простых таймеров. Например:
const start = performance.now () ;
//... run code...
const elapsed = performance.now () — start;
Примечание: нестандартное timeOriginсвойство возвращает отметку времени в формате времени Unix. Его можно использовать в Node.js и браузерном JavaScript, но не в IE и Safari.
performance.now () быстро становится непрактичным при управлении несколькими таймерами. Метод.mark () добавляет именованный объект объекта PerformanceMark в буфер производительности. Например:
performance.mark ('script: start’) ;
performance.mark ('p1: start’) ;
//... run process 1...
performance.mark ('p1: end’) ;
performance.mark ('p2: start’) ;
//... run process 2...
performance.mark ('p2: end’) ;
performance.mark ('script: end’) ;
Следующий код возвращает массив объектов меток:
const marks = performance.getEntriesByType ('mark’) ;
с entryType, nameи startTimeсвойствами:
[
{
entryType: «mark»,
name: «script: start»,
startTime: 100
},
{
entryType: «mark»,
name: «p1: start»,
startTime: 200
},
{
entryType: «mark»,
name: «p1: end»,
startTime: 300
},
...
]
Прошедшее время между двумя отметками можно рассчитать с помощью.measure () метода. Ему передается имя показателя, имя начальной метки (или nullдля использования нуля) и имя конечной метки (или nullдля использования текущего времени):
performance.measure ('p1', 'p1: start’, 'p1: end’) ;
performance.measure ('script’, null, 'script: end’) ;
Каждый вызов помещает объект PerformanceMeasure с рассчитанной длительностью в буфер производительности. Доступ к массиву мер можно получить, запустив:
const measures = performance.getEntriesByType ('measure’) ;
Пример:
[
{
entryType: «measure»,
name: «p1»,
startTime: 200,
duration: 100
},
{
entryType: «measure»,
name: «script»,
startTime: 0,
duration: 500
}
]
Объекты маркировки или измерения можно получить по имени с помощью.getEntriesByName () метода:
performance.getEntriesByName ('p1') ;
Другие методы:
.getEntries (): возвращает массив всех записей производительности.
.clearMarks ([name]): очистить названную метку (запустите без имени, чтобы очистить все метки)
.clearMeasures ([name]): очистить именованный показатель (запустите без имени, чтобы очистить все показатели)
PerformanceObserver может отслеживать изменения в буфере и запускать функцию при появлении определенных объектов. Функция наблюдателя определяется двумя параметрами:
list: записи наблюдателя
observer (необязательно):
function performanceHandler (list, observer) {
list.getEntries ().forEach (entry => {
console.log (`name: ${ entry.name }`) ;
console.log (`type: ${ entry.type }`) ;
console.log (`duration: ${ entry.duration }`) ;
// other code, e.g.
// send data via an Ajax request
}) ;
}
Эта функция передается новому PerformanceObserverобъекту. Затем.observe () метод устанавливает наблюдаемые entryTypes (обычно «mark», «measure»и/или «resource»):
let observer = new PerformanceObserver (performanceHandler) ;
observer.observe ({ entryTypes: [ 'mark’, 'measure’ ] }) ;
Функция performanceHandler () будет запускаться всякий раз, когда новая метка или объект измерения помещаются в буфер производительности.
API самопрофилирования
API самопрофилирования связан с API производительности и может помочь найти неэффективные или ненужные фоновые функции без необходимости вручную устанавливать метки и меры.
Пример кода:
// new profiler, 10ms sample rate
const profile = await performance.profile ({ sampleInterval: 10 }) ;
//... run code...
// stop profiler, get trace
const trace = await profile.stop () ;
Трассировка возвращает данные о том, какой сценарий, функция и номер строки выполнялись в каждый выбранный интервал. Повторные ссылки на один и тот же код могут указывать на возможность дальнейшей оптимизации.
В настоящее время API находится в стадии разработки (см. Статус Chrome) и может быть изменен.
Настройка производительности приложений
API производительности предлагает способ измерения скорости
Решение этих проблем с производительностью — другое дело, но книга SitePoint Jump Start Web Performance поможет. Он предлагает ряд быстрых закусок, простых рецептов и изменяющих жизнь диет, чтобы сделать ваш сайт более быстрым и отзывчивым.