Прогрессивные веб-приложения позволяют разработчикам создавать новый класс приложений, обеспечивающих надежный и высокопроизводительный пользовательский интерфейс. Но чтобы быть уверенным, что веб-приложение достигает желаемых показателей производительности, разработчикам необходим доступ к данным измерения производительности с высоким разрешением. Спецификация W3C Performance Timeline определяет такой интерфейс для браузеров, обеспечивающий программный доступ к данным синхронизации низкого уровня. Это открывает двери для некоторых интересных вариантов использования:
- оффлайн и индивидуальный анализ производительности
- сторонние инструменты анализа и визуализации производительности
- оценка производительности интегрирована в IDE и другие инструменты разработчика
Доступ к такого рода временным данным уже доступен в большинстве основных браузеров для определения времени навигации , времени использования ресурсов и времени пользователя . Новейшим дополнением является интерфейс наблюдателя производительности , который по сути представляет собой потоковый интерфейс для асинхронного сбора информации о времени низкого уровня по мере ее сбора браузером. Этот новый интерфейс предоставляет ряд важных преимуществ по сравнению с предыдущими методами доступа к временной шкале:
- Сегодня приложениям приходится периодически опрашивать и сравнивать сохраненные измерения, что обходится дорого. Этот интерфейс предлагает им обратный вызов. (Другими словами, нет необходимости проводить опрос). В результате приложения, использующие этот API, могут быть более отзывчивыми и эффективными.
- На него не распространяются ограничения буфера (большинство буферов по умолчанию имеют значение 150 элементов) и позволяют избежать состояний гонки между различными потребителями, которые могут захотеть изменить буфер.
- Уведомления наблюдателя за производительностью доставляются асинхронно, и браузер может отправлять их во время простоя, чтобы избежать конкуренции с критически важной работой по рендерингу.
Начиная с Chrome 52, интерфейс наблюдателя производительности включен по умолчанию . Давайте посмотрим, как его использовать.
<html>
<head>
<script>
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
// Display each reported measurement on console
if (console) {
console.log("Name: " + entry.name +
", Type: " + entry.entryType +
", Start: " + entry.startTime +
", Duration: " + entry.duration + "\n");
}
})
});
observer.observe({entryTypes: ['resource', 'mark', 'measure']});
performance.mark('registered-observer');
function clicked(elem) {
performance.measure('button clicked');
}
</script>
</head>
<body>
<button onclick="clicked(this)">Measure</button>
</body>
</html>
Эта простая страница начинается с тега скрипта, определяющего некоторый код JavaScript:
- Мы создаем экземпляр нового объекта
PerformanceObserver
и передаем функцию обработчика событий конструктору объекта. Конструктор инициализирует объект таким образом, что наш обработчик будет вызываться каждый раз, когда новый набор данных измерений будет готов к обработке (при этом данные измерений передаются в виде списка объектов). Обработчик здесь определен как анонимная функция, которая просто отображает отформатированные данные измерений на консоли. В реальном сценарии эти данные могут храниться в облаке для последующего анализа или передаваться в интерактивный инструмент визуализации. - Мы регистрируем интересующие нас типы временных событий с помощью метода
observe()
и вызываем методmark()
, чтобы отметить момент регистрации, который мы будем считать началом наших временных интервалов. - Мы определяем обработчик кликов для кнопки, определенной в теле страницы. Этот обработчик кликов вызывает
measure()
для сбора данных о времени нажатия кнопки.
В теле страницы мы определяем кнопку, назначаем обработчик кликов событию onclick
, и все готово.
Теперь, если мы загрузим страницу и откроем панель Chrome DevTools, чтобы просмотреть консоль JavaScript, каждый раз, когда мы нажимаем кнопку, будет измеряться производительность. И поскольку мы зарегистрировались для наблюдения за такими измерениями, они асинхронно пересылаются нашему обработчику событий без необходимости опроса временной шкалы , которая отображает измерения на консоли по мере их возникновения:
start
значение представляет собой начальную метку времени для событий типа mark
(из которых в этом приложении есть только одно). События с measure
типа не имеют собственного времени начала; они представляют собой измерения времени, сделанные относительно последнего события mark
. Таким образом, значения длительности, показанные здесь, представляют собой время, прошедшее между вызовом mark()
, который служит начальной точкой общего интервала, и несколькими последующими вызовами measure()
.
Как видите, этот API довольно прост и предлагает возможность собирать отфильтрованные данные о производительности в высоком разрешении в реальном времени без опроса, что должно открыть путь к более эффективным инструментам повышения производительности для веб-приложений.