Создание сайтов в Москве. Как сделать ваш сайт быстрее с помощью Performance API

В этом руководстве объясняется, как использовать Performance API для записи статистики, подобной DevTool, от реальных пользователей, обращающихся к вашему приложению.

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

Введение в 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 (скрипты, использующие его, должны запускаться с —allow-hrtimeразрешением).

Разве недостаточно Date () хорошо?

Возможно, вы видели примеры использования этой Date () функции для записи прошедшего времени. Например:

const start = new Date () ;

//... run code...

const elapsed = new Date () — start;

Однако Date () расчеты ограничены ближайшей миллисекундой и основаны на системном времени, которое ОС может обновить в любой момент.

Performance API использует отдельный таймер с более высоким разрешением, который может записывать доли миллисекунды. Он также предлагает метрики, которые было бы невозможно записать иначе, например, время перенаправления и поиска DNS.

Запись показателей производительности

Вычисление метрик производительности в коде на стороне клиента полезно, если вы можете записать его где-нибудь. Вы можете отправлять статистику на свой сервер для анализа с помощью запросов Ajax Fetch / XmlHttpRequest или Beacon API.

В качестве альтернативы, большинство аналитических систем предлагают настраиваемые API-интерфейсы, подобные событиям, для записи времени. Например, Google Analytics User Timings API может записывать время DOMContentLoaded, передавая категорию ('pageload’), имя переменной («DOMready») и значение:

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’) ;

Или получить к нему доступ, передав URL-адрес страницы (window.location) в getEntriesByName () method:

const pagePerf = performance.getEntriesByName (window.location) ;

Оба возвращают массив с одним элементом, содержащим объект со свойствами только для чтения. Например:

[

{

name: «https: //site.com/»,

initiatorType: «navigation»,

entryType: «navigation»,

initiatorType: «navigation»,

type: «navigate»,

nextHopProtocol: «h2»,

startTime: 0

...

}

]

Объект включает в себя свойства идентификации ресурса:

имущество описание

имя URL-адрес ресурса

тип записи тип производительности — «navigation»для страницы, «resource»для актива

тип инициатора ресурс, инициировавший загрузку — «navigation»для страницы

nextHopProtocol сетевой протокол

serverTiming массив объектов PerformanceServerTiming

Примечание. PerformanceServerTiming name, description, и durationметрики записываются в Server-Timingзаголовок HTTP ответом сервера.

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

имущество описание

время начала отметка времени начала выборки — 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 в буфер производительности, когда:

происходит первая краска: браузер рисует первый пиксель, и

происходит first-contentful-paint: браузер рисует первый элемент содержимого DOM

Оба объекта возвращаются в массиве при запуске:

const paintPerf = performance.getEntriesByType ('paint’) ;

Пример результата:

[

{

«name»: «first-paint»,

«entryType»: «paint»,

«startTime»: 125

},

{

«name»: «first-contentful-paint»,

«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 производительности предлагает способ измерения скорости веб-сайта и приложений на реальных устройствах, используемых реальными людьми в разных местах с различными подключениями. Это позволяет легко сопоставлять метрики, подобные DevTool, для всех и выявлять потенциальные узкие места.

Решение этих проблем с производительностью — другое дело, но книга SitePoint Jump Start Web Performance поможет. Он предлагает ряд быстрых закусок, простых рецептов и изменяющих жизнь диет, чтобы сделать ваш сайт более быстрым и отзывчивым.

Делитесь нашими материалами с друзьями!

 

 

Заказать разработку сайта