Как сделать ваш сайт быстрее с помощью Performance API

Performance API Изучение

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

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

Введение в Performance API

API Performance использует буфер для записи DevTool типа метрик в свойствах объекта в определенные моменты в жизни вашей веб — странице. Эти пункты включают:

  1. Навигация по страницам: запись перенаправлений загрузки страниц, подключений, рукопожатий, событий DOM и т.д.
  2. Загрузка ресурсов: запись загрузки ресурсов, таких как изображения, CSS, скрипты и вызовы Ajax.
  3. Показатели отрисовки: запись информации о рендеринге браузера.
  4. Настраиваемая производительность: записывайте произвольное время обработки приложений, чтобы найти медленные функции.

Все 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-интерфейсы, подобные событиям, для записи времени. Например, API пользовательского времени Google Analytics может записывать время до DOMContentLoaded, передав категорию ( ’pageload’), имя переменной ( «DOMready») и значение:

const pageload = performance.getEntriesByType( 'navigation' )[0];

ga('send', 'timing', 'pageload', 'DOMready', pageload.domContentLoadedEventStart);

В этом примере используется API времени навигации по страницам. так что начнем с этого…

Время навигации по странице

Тестирование вашего сайта на быстром соединении вряд ли будет показателем пользовательского опыта. Вкладка DevTools в браузере » Сеть » позволяет регулировать скорость, но не может имитировать плохие или прерывистые сигналы 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
    ...
  }
]

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

property описание
название URL ресурса
entryType тип производительности — «navigation»для страницы, «resource»для актива
initiatorType ресурс, инициировавший загрузку — «navigation»для страницы
nextHopProtocol сетевой протокол
serverTiming массив объектов PerformanceServerTiming

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

Объект включает свойства времени ресурса в миллисекундах имущество

property описание
время начала отметка времени начала загрузки — 0для страницы
workerStart отметка времени перед запуском Service Worker
redirectStart отметка времени первого перенаправления
redirectEnd отметка времени после получения последнего байта последнего перенаправления
fetchStart отметка времени перед выборкой ресурса
domainLookupStart отметка времени перед поиском в DNS
domainLookupEnd отметка времени после поиска в DNS
connectStart отметка времени перед установкой соединения с сервером
connectEnd отметка времени после установления соединения с сервером
secureConnectionStart отметка времени перед подтверждением SSL
requestStart отметка времени перед запросом браузера
responseStart отметка времени, когда браузер получает первый байт данных
responseEnd отметка времени после получения последнего байта данных
продолжительность время, прошедшее между startTime и responseEnd

Объект включает свойства размера загрузки в байтах:

property описание
transferSize размер ресурса, включая заголовок и тело
encodedBodySize размер тела ресурса перед распаковкой
decodedBodySize размер тела ресурса после распаковки

Наконец, объект включает дополнительную навигацию и свойства события DOM (недоступно в Safari):

property описание
тип либо «navigate», «reload», «back_forward»или»prerender»
redirectCount количество перенаправлений
unloadEventStart отметка времени перед unloadсобытием предыдущего документа
unloadEventEnd отметка времени после unloadсобытия предыдущего документа
domInteractive отметка времени, когда разбор 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;

});

Время ресурса страницы

Resource Timing API помещает 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) измеряет, сколько времени требуется для визуализации контента после того, как пользователь перейдет на вашу страницу. Performance раздел панели DevTool Маяка Chrome показывает метрику. Google считает, что время FCP менее двух секунд является хорошим, и ваша страница будет отображаться быстрее, чем 75% Интернета.

Paint Timing API помещает две записи и два объекта PerformancePaintTiming в буфер производительности в следующих случаях:

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

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

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

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

[
  {
    "name": "first-paint",
    "entryType": "paint",
    "startTime": 125
  },
  {
    "name": "first-contentful-paint",
    "entryType": "paint",
    "startTime": 127
  }
]

Начальное время является относительно начальной загрузки страницы.

Пользовательское время

Performance 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 может наблюдать за изменениями в буфер и запустить функцию, когда появляются конкретные объекты. Функция наблюдателя определяется двумя параметрами:

  1. list: записи наблюдателя
  2. 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

Self-профилирование API связан с API Performance и может помочь найти неэффективные или ненужные фоновые функции без необходимости вручную установленных знаков и мер.

Пример кода:

// 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 ) и может быть изменен.

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

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

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

Читайте также:  React Query 3: Руководство по получению и управлению данными
Оцените статью
bestprogrammer.ru
Добавить комментарий