Понимание вашего веб-приложения
Высокопроизводительные веб-приложения имеют решающее значение для удобства работы пользователей. Поскольку веб-приложения становятся все более и более сложными, понимание влияния на производительность имеет жизненно важное значение для создания убедительного опыта. За последние несколько лет в браузере появилось множество различных API-интерфейсов, которые помогают анализировать производительность сети, время загрузки и т. д., но они не обязательно дают подробную информацию с достаточной гибкостью, чтобы определить, что замедляет работу вашего приложения. . Введите API пользовательского времени , который предоставляет механизм, который вы можете использовать для инструментирования вашего веб-приложения, чтобы определить, где ваше приложение тратит свое время. В этой статье мы рассмотрим API и примеры его использования.
Невозможно оптимизировать то, что нельзя измерить
Первый шаг в ускорении медленного веб-приложения — выяснить, на что тратится время. Измерение влияния времени на области кода Javascript — идеальный способ выявления «горячих точек», а также первый шаг к поиску способов повышения производительности. К счастью, API User Timing позволяет вставлять вызовы API в разные части вашего Javascript, а затем извлекать подробные данные о времени, которые можно использовать для оптимизации.
Время высокого разрешения и now()
Фундаментальной частью точного измерения времени является точность. Раньше у нас был тайминг, основанный на измерении в миллисекундах, и это нормально, но создание сайта с частотой 60 FPS без рывков означает, что каждый кадр должен быть отрисован за 16 мс. Поэтому, когда у вас есть только миллисекундная точность, ей не хватает точности, необходимой для хорошего анализа. Введите «Время высокого разрешения» — новый тип синхронизации, встроенный в современные браузеры. Время высокого разрешения дает нам метки времени с плавающей запятой, которые могут быть точными до микросекундного разрешения — в тысячу раз лучше, чем раньше.
Чтобы получить текущее время в вашем веб-приложении, вызовите метод now()
, который образует расширение интерфейса Performance . Следующий код показывает, как это сделать:
var myTime = window.performance.now();
Существует еще один интерфейс под названием PerformanceTiming , который предоставляет несколько различных моментов времени, связанных с загрузкой вашего веб-приложения. Метод now()
возвращает время, прошедшее с момента наступления времени navigationStart
в PerformanceTiming .
Тип DOMHighResTimeStamp.
Раньше при попытке синхронизировать веб-приложения вы использовали что-то вроде Date.now()
которое возвращает DOMTimeStamp . DOMTimeStamp возвращает целое число миллисекунд в качестве своего значения. Чтобы обеспечить более высокую точность, необходимую для времени высокого разрешения, был введен новый тип под названием DOMHighResTimeStamp . Этот тип представляет собой значение с плавающей запятой, которое также возвращает время в миллисекундах. Но поскольку это число с плавающей запятой, значение может представлять собой дробные миллисекунды и, таким образом, может давать точность в одну тысячную миллисекунду.
Пользовательский интерфейс синхронизации
Итак, теперь, когда у нас есть отметки времени с высоким разрешением, давайте воспользуемся интерфейсом User Timing, чтобы получить информацию о времени.
Интерфейс User Timing предоставляет функции, которые позволяют нам вызывать методы в разных местах нашего приложения, которые могут предоставить навигационную цепочку в стиле Гензеля и Гретель, позволяющую нам отслеживать, на что тратится время.
Использование mark()
Метод mark()
— основной инструмент в нашем наборе инструментов временного анализа. Функция mark()
сохраняет для нас отметку времени. Что очень полезно в mark()
так это то, что мы можем назвать отметку времени, и API запомнит имя и отметку времени как единое целое.
Вызов mark()
в различных местах вашего приложения позволяет вам определить, сколько времени вам потребовалось для достижения этой «отметки» в вашем веб-приложении.
В спецификации приводится ряд предлагаемых имен для отметок, которые могут быть интересны и не требуют пояснений, например mark_fully_loaded
, mark_fully_visible
, mark_above_the_fold
и т. д.
Например, мы могли бы установить отметку о полной загрузке приложения, используя следующий код:
window.performance.mark('mark_fully_loaded');
Устанавливая именные метки в нашем веб-приложении, мы можем собрать целый набор данных о времени и проанализировать их на досуге, чтобы определить, что приложение делает и когда.
Вычисление измерений с помощью measure()
После того, как вы установили несколько временных меток, вам захочется узнать время, прошедшее между ними. Для этого вы используете метод measure()
.
Метод measure()
вычисляет время, прошедшее между отметками, а также может измерять время между вашей отметкой и любым из известных названий событий в интерфейсе PerformanceTiming .
Например, вы можете определить время от завершения DOM до полной загрузки состояния вашего приложения, используя такой код:
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
Когда вы вызываете measure()
она сохраняет результат независимо от установленных вами отметок, поэтому вы можете получить его позже. Сохраняя время простоя во время работы вашего приложения, приложение остается отзывчивым, и вы можете выгрузить все данные после того, как ваше приложение завершит некоторую работу, чтобы их можно было проанализировать позже.
Отбрасывание меток с помощью clearMarks()
Иногда полезно иметь возможность избавиться от множества установленных вами отметок. Например, вы можете выполнять пакетные запуски своего веб-приложения и поэтому хотите начинать каждый запуск заново.
Достаточно легко избавиться от любых установленных вами отметок, вызвав clearMarks()
.
Таким образом, приведенный ниже пример кода уничтожит все имеющиеся у вас отметки, и вы сможете снова настроить отсчет времени, если захотите.
window.performance.clearMarks();
Конечно, есть сценарии, в которых вам, возможно, не захочется стирать все свои отметки. Поэтому, если вы хотите избавиться от определенных отметок, вы можете просто передать имя отметки, которую хотите удалить. Например, код ниже:
window.performance.clearMarks('mark_fully_loaded');
избавляется от отметки, которую мы установили в первом примере, оставляя все остальные отметки, которые мы установили, неизменными.
Возможно, вам также захочется избавиться от любых сделанных вами измерений, и для этого существует соответствующий метод, называемыйclearMeasures clearMeasures()
. Он работает точно так же, как clearMarks()
, но вместо этого работает с любыми сделанными вами измерениями. Например, код:
window.performance.clearMeasures('measure_load_from_dom');
удалит меру, которую мы сделали в приведенном выше примере measure()
. Если вы хотите удалить все меры, это работает так же, как и clearMarks()
— вы просто вызываете clearMeasures()
без аргументов.
Получение данных о времени
Устанавливать отметки и измерять интервалы — это хорошо, но в какой-то момент вам захочется получить эти временные данные для проведения некоторого анализа. Это тоже очень просто: все, что вам нужно сделать, это использовать интерфейс PerformanceTimeline
.
Например, метод getEntriesByType()
позволяет нам получить все значения времени отметки или все значения времени измерения в виде списка, чтобы мы могли перебирать его и переваривать данные. Что приятно, так это то, что список возвращается в хронологическом порядке, поэтому вы можете видеть отметки в том порядке, в котором они были отмечены в вашем веб-приложении.
Код ниже:
var items = window.performance.getEntriesByType('mark');
возвращает нам список всех отметок, которые были достигнуты в нашем веб-приложении, а код:
var items = window.performance.getEntriesByType('measure');
возвращает нам список всех мер, которые мы сделали.
Вы также можете получить список записей, используя определенное имя, которое вы им дали. Так, например, код:
var items = window.performance.getEntriesByName('mark_fully_loaded');
вернет нам список с одним элементом, содержащим отметку времени «mark_fully_loaded» в свойстве startTime
.
Время запроса XHR (пример)
Теперь, когда у нас есть хорошее представление об API пользовательского времени, мы можем использовать его для анализа того, сколько времени занимают все наши XMLHttpRequests в нашем веб-приложении.
Сначала мы изменим все наши запросы send()
, чтобы они выдавали вызов функции, устанавливающей отметки, и в то же время заменим наши обратные вызовы успеха вызовом функции, которая устанавливает другую отметку, а затем генерирует меру продолжительности запроса. взял.
Обычно наш XMLHttpRequest будет выглядеть примерно так:
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
do_something(e.responseText);
}
myReq.send();
В нашем примере мы добавим глобальный счетчик для отслеживания количества запросов, а также будем использовать его для хранения показателя для каждого сделанного запроса. Код для этого выглядит так:
var reqCnt = 0;
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
window.performance.mark('mark_end_xhr');
reqCnt++;
window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();
Приведенный выше код генерирует меру с уникальным значением имени для каждого отправляемого нами XMLHttpRequest. Мы предполагаем, что запросы выполняются последовательно — код для параллельных запросов должен быть немного более сложным для обработки запросов, которые возвращаются не по порядку, мы оставим это в качестве упражнения для читателя.
Как только веб-приложение выполнит несколько запросов, мы сможем выгрузить их все на консоль, используя приведенный ниже код:
var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
var req = items[i];
console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}
Заключение
API User Timing предоставляет вам множество отличных инструментов, которые можно применить к любому аспекту вашего веб-приложения. Сужение «горячих точек» в вашем приложении может быть легко достигнуто путем распределения вызовов API по всему веб-приложению и последующей обработки сгенерированных данных о времени, чтобы создать четкое представление о том, на что тратится время. Но что, если ваш браузер не поддерживает этот API? Нет проблем, здесь вы можете найти отличный полифил , который очень хорошо эмулирует API, а также прекрасно работает с webpagetest.org . Так чего же вы ждете? Попробуйте API User Timing в своих приложениях прямо сейчас, вы поймете, как их ускорить, и ваши пользователи будут вам благодарны за то, что вы сделали их работу намного лучше.