Начало работы с JavaScript Performance API
Development, Java | Комментировать запись
Производительность – один из важнейших показателей работы сайта. У вас может быть лучший сайт в мире, но если он загружается 2 минуты, никто его не увидит – никто не станет дожидаться, пока он откроется.
Однако если ваш сайт загружается 2 минуты, найти и устранить причину не составит труда. Гораздо сложнее оптимизировать сайт, среднее время загрузки которого – 1 секунда, а вы хотите сократить его до 0,85 секунды.
Существует множество инструментов, которые могут помочь вам понять, как приложение работает локально. Performance API предоставляет детальное представление о работе веб-страниц в среде производства. Вы можете получить реальные данные и увидеть, как ваш сайт работает в разных браузерах, сетях и даже в разных частях мира!
Performance API часто называют составным. Он содержит в себе слишком много всего, чтобы описать это всё в одной статье. В этом руководстве мы рассмотрим самые основные функции, которые помогут вам начать мониторинг производительности.
API развивается, и в будущем в нем появится много новых функций, а другие функции, в свою очередь, устареют. Все составные интерфейсы Performance API приближаются к уровню 2; часть из них уже реализована, часть пока остается в разработке. Поэтому рекомендуем регулярно проверять сайт MDN или W3C на наличие свежих обновлений.
Читайте также: Получение данных с помощью JavaScript Fetch API
Как получить доступ к данным о производительности
Метод 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: пиксели, отображаемые на экране.
- 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 //}
Примечание: Если вам нужна информация более высокого уровня о производительности сайта, вы также можете вызвать performance.toJSON().
Аудит функций
Самым основным инструментом аудита определенных функций 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')
Вот один из ресурсов, найденных на Alligator.io:
{ 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 (это большой предел API синхронизации ресурсов). Таким образом, следующие свойства всегда будут возвращать 0: redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart и responseStart.
paint API
Paint API относится к событиям, которые рисуют пиксели в окне. Как мы видели в предыдущем фрагменте, у нас есть доступ к First Time to Paint и First Contentful Paint. Если вы работали с инструментами оптимизации внешнего интерфейса, такими как Lighthouse, вы должны быть знакомы с этими терминами. First Time to Paint – это когда на экране пользователя появляется первый пиксель. First Contentful Paint, первая содержательная отрисовка — это когда элемент, определенный в DOM, впервые визуализируется. Чтобы оптимизировать первую содержательную отрисовку, вы можете уменьшить количество скриптов и таблиц стилей, блокирующих рендеринг, использовать кэширование HTTP, оптимизировать загрузку JavaScript и многое другое!
Это полезные показатели, но они довольно ограничены, если вы пытаетесь понять, что видят ваши пользователи. Чтобы иметь хорошее представление о восприятии производительности вашим пользователем, нам нужно объединить несколько показателей.
Заключение
Performance API огромный и быстро меняется. Если вы хотите по-настоящему глубоко изучить эту тему, вам следует посетить страницу рабочей группы, где вы можете найти самые свежие проекты и рекомендации.
Tags: API, Javascript