DevGang
Авторизоваться

Как начать работу с Performance API в JavaScript

Производительность, производительность, производительность. У вас может быть лучший сайт в мире, но если загрузка займет 2 минуты, его никто не увидит. Если ваш сайт загружается за 2 минуты, вероятно, не составит труда понять, почему. Оптимизация сложнее, когда вы пытаетесь снизить среднее время загрузки с 1 до 0,85 секунды.

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

Performance API часто описывается как совокупность API. Слишком много вещей, чтобы описать все это в одной статье. В этом посте мы покажем самые основные функции, которые помогут вам начать мониторинг производительности.

API развивается, и есть много новых функций и устаревших функций. 2-й уровень всех API-интерфейсов для повышения производительности; некоторые из них частично реализованы, некоторые все еще являются черновиками. Поэтому вам следует регулярно проверять MDN или веб-сайт W3C на наличие последних обновлений.

Как получить доступ к данным о производительности

performance.now

Самый простой способ измерить производительность программы - это использовать performance.now(). Метод вернет текущее время с разрешением менее миллисекунды. Если вы хотите узнать больше времени с высоким разрешением, я настоятельно рекомендую прочитать проект редактора W3C на эту тему.

performance.now позволяет вам измерить только то, что находится в вашем JavaScript коде (то есть производительность пользователя). Позже в этом посте я приведу пример использования performance.now.

Для доступа к различным событиям DOM и браузера у нас есть 3 функции:

getEntries() возвращает все доступные записи производительности. Попробуйте запустить performance.getEntries() на текущей странице, и вы увидите большой массив. Первоначально, большинство записей будут относиться ко всем изображениям, сценариям и другим вещам, которые загружаются страницей (иначе ресурсы).

const tenthEntry = performance.getEntries()[10]
// on Alligator.io it will return the following object
// { initiatorType: "script",
// nextHopProtocol: "h2",
// workerStart: 526.8099999520928,
// redirectStart: 0,
// ....
// decodedBodySize: 0,
// serverTiming: [],
// name: "https://d33wubrfki0l68.cloudfront.net/bundles/e2203d1b1c14952473222bcff4c58a8bd9fef14a.js",
// entryType: "resource",
// startTime: 315.5049999477342,
// duration: 231.48499999661
//}
// We can see this is a resource entry for a script loaded from cloudfront

getEntriesByType() похож на getEntries(), но даст вам возможность отфильтровать результаты.

Вы можете запросить 6 типов:

  • frame: очень экспериментальная функция, которая позволяет разработчикам получать данные о том, сколько работы выполняется браузером в одном цикле событий. Если браузер выполняет слишком много работы за один цикл, частота кадров упадет, а пользовательский интерфейс будет плохим.
  • resource: это относится ко всем ресурсам, которые загружаются сайтом.
  • mark: это пользовательские маркеры, которые можно использовать для расчета скорости вашего кода.
  • measure: меры позволяют нам легко измерить разницу между двумя метками.
  • paint: записи paint относятся к пикселям, отображаемым на экране.
  • longtask: Длинные задачи - это любые задачи, выполнение которых занимает более 50 мс.

Мы рассмотрим некоторые из этих типов в следующих разделах. Вот простой пример для начала:

const paintEntries = performance.getEntriesByType('paint')
// paint Entries[0] equals {
//    name: "first-paint",
//    entryType: "paint",
//    startTime: 342.160000000149,
//    duration: 0,
//    }
// paintEntries[1] equals {
//    name: "first-contentful-paint",
//    entryType: "paint",
//    startTime: 342.160000000149,
//    duration: 0,
// }

getEntriesByName(entryName) фильтрует все записи по имени.

const nativeLogoPerfEntry = performance.getEntriesByName('https://alligator.io/images/alligator-logo3.svg')[0];
// It will return performance information related to the logo's performance:
// {initiatorType: "img",
// nextHopProtocol: "",
// workerStart: 539.6649999311194,
// ........
// name: "https://alligator.io/images/alligator-logo3.svg",
// entryType: "resource",
// startTime: 539.5149999530986,
// duration: 94.24000000581145
//}

Аудит ваших функций

Для аудита определенных функций JavaScript наиболее простым инструментом является то, что мы описали выше, performance.now().

Вот пример использования:

const firstNow = performance.now()
// This loop is just to simulate slow calculations
for (let i = 0; i < 100000; i++){
  var ii = Math.sqrt(i)
}
const secondNow = performance.now()

const howLongDidOurLoopTake = secondNow - firstNow
// on my laptop it returns howLongDidOurLoopTake == 4.08500000089407 in milliseconds

Проблема now в том, что управлять им немного сложно, если у вас много измерений. Более полезный инструмент mark, который создает некоторые записи производительности, которые вы можете запросить позже. Затем вы можете комбинировать маркеры и создавать новые записи, используя measure.

performance.mark('beginSquareRootLoop');
// This loop is just to simulate slow calculations
for (let i = 0; i < 1000000; i++){
  var ii = Math.sqrt(i);
}
performance.mark('endSquareRootLoop');
// Then anywhere in your code you can use

// We create a new entry called measureSquareRootLoop which combines our two marks
performance.measure('measureSquareRootLoop','beginSquareRootLoop', 'endSquareRootLoop');

console.log(performance.getEntriesByName('beginSquareRootLoop'));
// {detail: null,
// name: "beginSquareRootLoop",
// entryType: "mark",
// startTime: 3745.360000000801,
// duration: 0}

console.log(performance.getEntriesByName('measureSquareRootLoop'));
// {detail: null,
// name: "measureSquareRootLoop",
// entryType: "measure",
// startTime: 3745.360000000801, This is the same as beginSquareRootLoop
// duration: 9.904999984428287 shows the time it took to get from beginSquareRootLoop to endSquareRootLoop
//}

Данные навигации

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

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

В моем браузере я получаю:

{
  unloadEventStart: 213.41000002576038,
  unloadEventEnd: 213.41000002576038,
  domInteractive: 975.8100000326522,
  domContentLoadedEventStart: 982.2649999987334,
  domContentLoadedEventEnd: 1217.9650000180118,
  domComplete: 2000.960000033956,
  loadEventStart: 2001.044999982696,
  loadEventEnd: 2008.6500000325032,
  type: "reload",
  redirectCount: 0,
  initiatorType: "navigation",
  nextHopProtocol: "",
  workerStart: 2.5550000136718154,
  redirectStart: 0,
  redirectEnd: 0,
  fetchStart: 2.5599999935366213,
  domainLookupStart: 2.5599999935366213,
  domainLookupEnd: 2.5599999935366213,
  connectStart: 2.5599999935366213,
  connectEnd: 2.5599999935366213,
  secureConnectionStart: 0,
  requestStart: 2.5599999935366213,
  responseStart: 107.46500000823289,
  responseEnd: 214.3950000172481,
  transferSize: 0,
  encodedBodySize: 0,
  decodedBodySize: 0,
  serverTiming: [],
  name: "https://alligator.io/",
  entryType: "navigation",
  startTime: 0,
  duration: 2008.6500000325032
}
Визуализация временной шкалы навигации
Визуализация временной шкалы навигации

Ресурс

Каждый раз, когда ресурс загружается страницей, мы можем найти его след в записях производительности. Все, что нам нужно сделать, чтобы получить их, это запустить performance.getEntriesByType('resource'). Это включает в себя изображения, сценарии, файлы CSS и многое другое. Так, например, если мы хотим сосредоточиться на производительности изображений на сайте, мы можем запустить:

performance.getEntriesByType('resource').filter(resource=> resource.initiatorType == 'img')

Вот один из ресурсов, найденных на моем сайте:

{
    initiatorType: "img",
    nextHopProtocol: "h2",
    workerStart: 551.2149999849498,
    redirectStart: 0,
    redirectEnd: 0,
    fetchStart: 551.3149999896996,
    domainLookupStart: 0,
    domainLookupEnd: 0,
    connectStart: 0,
    connectEnd: 0,
    secureConnectionStart: 0,
    requestStart: 0,
    responseStart: 0,
    responseEnd: 560.1850000093691,
    transferSize: 0,
    encodedBodySize: 0,
    decodedBodySize: 0,
    serverTiming: [],
    name: "https://d33wubrfki0l68.cloudfront.net/39d2d2905588dad289b228deb021d51449f6143d/a3baf/images/logos/gatsby-logo.svg",
    entryType: "resource",
    startTime: 222.0450000022538,
    duration: 338.1400000071153
}

Эта запись имеет множество значений 0, как вы можете видеть, потому что мы ограничены CORS. Поэтому следующие свойства всегда будут возвращать 0: redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart и responseStart.

Отрисовка

API рисования относится к событиям, которые рисуют пиксели в окне. Как мы видели в предыдущем фрагменте, у нас есть доступ к First Time to Paint и First Contentful Paint. Если вы работали с инструментами внешней оптимизации, такими как Lighthouse, вы можете быть знакомы с этими терминами. First Time to Paint - это когда первый пиксель появляется на экране пользователя. First Contentful Paint - это когда элемент, определенный в DOM, начал отображается. Для оптимизации First Time to Paint вы можете уменьшить количество сценариев и таблиц стилей, блокирующих рендеринг, использовать HTTP-кэширование, оптимизировать загрузку JavaScript и многое другое!

Это полезные показатели, но они довольно ограничены, если вы пытаетесь понять, что видят ваши пользователи. Чтобы иметь представление о восприятии производительности вашего пользователя, нам нужно объединить несколько показателей.

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

Источник:

#JavaScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

Поделитесь своим опытом, расскажите о новом инструменте, библиотеке или фреймворке. Для этого не обязательно становится постоянным автором.

Попробовать

Оплатив хостинг 25$ в подарок вы получите 100$ на счет

Получить