В этой лабораторной работе вы узнаете, как использовать Google Analytics и API пользовательского времени для измерения реальной производительности вашего веб-сайта или приложения и оптимизировать их для улучшения пользовательского опыта.
Такие инструменты, как WebPagetest.org , являются отличным началом для оптимизации производительности, но настоящим испытанием производительности сайта всегда будут реальные данные от реальных пользователей.
Если у вас есть веб-сайт, вы, скорее всего, уже используете Google Analytics для измерения трафика, а также таких показателей, как использование устройств и браузеров. С помощью небольшого дополнительного кода вы можете добавить к этому метрики производительности.
Чему вы научитесь
- Как точно и эффективно измерять показатели производительности с помощью API User Timings
- Как отправить эти данные в Google Analytics, чтобы их можно было включить в ваши отчеты
Что вам понадобится
- Браузер с консолью разработчика
- Веб-сервер для Chrome или используйте собственный веб-сервер по вашему выбору
- Пример кода
- Текстовый редактор
- (Необязательно) аккаунт Google Analytics
Как вы будете использовать это руководство?
Как бы вы оценили свой опыт создания веб-сайтов или приложений?
Вы можете либо загрузить все примеры кода на свой компьютер...
...или клонируйте репозиторий GitHub из командной строки.
git clone https://github.com/googlecodelabs/performance-analytics.git
Пример кода разделён на подкаталоги, соответствующие каждому из пронумерованных шагов в этой лабораторной работе. Вы можете использовать это для быстрого перехода по фрагментам работы или проверки корректности вашей реализации.
Если у вас есть доступ к программе сравнения, вы можете использовать ее, чтобы увидеть, что именно изменилось от шага к шагу.
В этой лабораторной работе по кодированию вы возьмете один HTML-файл, который загрузит следующие ресурсы:
- Веб-шрифты
- Таблицы стилей
- Изображения
- JavaScript
И вам предстоит написать новый код, который будет измерять ключевые показатели производительности для каждого из этих типов активов.
Соображения эффективности активов
Если вы когда-либо читали что-нибудь об оптимизации производительности, вы, вероятно, уже знаете, что каждый из этих типов активов имеет свои собственные особенности и может по-разному влиять на общую воспринимаемую производительность.
CSS
Например, таблицы стилей блокируют отрисовку всех элементов DOM, расположенных после них. Это означает, что браузеру приходится запросить таблицу стилей, загрузить её и проанализировать, прежде чем он сможет отобразить какой-либо контент DOM, расположенный после неё. По этой причине обычно лучше всего размещать таблицы стилей в разделе <head> документа. Кроме того, из-за блокирующей природы CSS часто рекомендуется размещать в разделе <head> только критически важные CSS-стили, а затем асинхронно загружать некритичные CSS-стили.
JavaScript
JavaScript, с другой стороны, не блокирует рендеринг, но блокирует парсинг и построение DOM. Это необходимо, поскольку JavaScript может изменять DOM, а это означает, что каждый раз, когда браузер видит тег <script> (за исключением асинхронных скриптов), он должен выполнить код, прежде чем перейти к следующему тегу. Если тег <script> ссылается на внешний файл JavaScript, он должен загрузить и выполнить код, прежде чем перейти к следующему тегу.
По этой причине часто рекомендуется загружать JavaScript непосредственно перед закрывающимся тегом </body>, чтобы большая часть DOM была доступна как можно быстрее.
Веб-шрифты
Если вы загружаете веб-шрифты, вы также можете заблокировать отображение документа до тех пор, пока шрифт не станет доступен для использования. В этом случае крайне важно понимать, сколько времени это занимает у ваших пользователей. Веб-шрифт может загружаться быстро для вас, но очень медленно для большинства посетителей вашего сайта. Именно поэтому так важно измерять и принимать решения на основе реальных данных.
Изображения
Наконец, изображения действительно могут оживить сайт, но зачастую они загружаются дольше всего. Понимание того, что это на самом деле означает, и умение выявлять взаимосвязи между моделями использования и временем загрузки страниц крайне важно для понимания того, как оптимизировать сайт.
Первым шагом в этой лабораторной работе по кодированию является просмотр демонстрационной страницы перед добавлением кода для измерения производительности.
Чтобы просмотреть демо, создайте новую папку и добавьте в неё файл index.html. Затем скопируйте и вставьте приведённый ниже код в файл index.html.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Performance Analytics Demo</title>
<!-- Start fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700,400italic" rel="stylesheet">
<!-- End fonts -->
<!-- Start CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
<style>
body { font-family: Roboto, sans-serif; margin: 1em; }
img { float: left; height: auto; width: 33.33%; }
.gallery { overflow: hidden; }
</style>
<!-- End CSS -->
</head>
<body>
<div class="container">
<!-- Start images -->
<div class="gallery">
<img src="http://lorempixel.com/380/200/animals/1/">
<img src="http://lorempixel.com/380/200/animals/2/">
<img src="http://lorempixel.com/380/200/animals/3/">
</div>
<!-- End images -->
<h1>Performance Analytics Demo</h1>
<p>Real performance data from real users.</p>
</div>
<!-- Start JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<!-- End JavaScript -->
</body>
</html>Затем откройте «Веб-сервер для Chrome» и запустите локальный сервер в только что созданном каталоге. Убедитесь, что установлен флажок «Автоматически показывать index.html».

Теперь вы можете перейти по адресу http://127.0.0.1:8887/ в браузере и увидеть демонстрационный файл. Он должен выглядеть примерно так:

После запуска демо-страницы уделите немного времени изучению кода и отметьте загрузку всех типов ресурсов. На следующих нескольких шагах вы добавите код для отслеживания момента загрузки этих ресурсов и возможности взаимодействия с ними пользователя.
Как упоминалось ранее в разделе, посвященном вопросам производительности ресурсов, CSS блокирует рендеринг элементов DOM, а также выполнение скриптов, которые идут после него в DOM.
Демонстрационный файл, который вы только что создали, содержит следующий CSS-код, который ссылается на Bootstrap и несколько встроенных стилей.
<!-- Start CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
<style>
body { font-family: Roboto, sans-serif; margin: 1em; }
img { float: left; height: auto; width: 33.33%; }
.gallery { overflow: hidden; }
</style>
<!-- End CSS --> Поскольку CSS блокирует как рендеринг элементов DOM, так и выполнение скриптов, можно определить, когда CSS завершает блокировку, добавив тег <script> сразу после CSS, который хранит текущее время.
Это можно сделать, создав переменную и присвоив ей new Date() , но благодаря API User Timings есть гораздо более простой способ: метод performance.mark .
Чтобы обозначить момент, когда CSS завершает блокировку рендеринга и выполнения скрипта, добавьте следующую строку кода непосредственно перед закрывающим комментарием <!-- End CSS --> .
<script>performance.mark('css:unblock');</script> Метод performance.mark создаёт метку времени высокого разрешения в этот конкретный момент времени и связывает её с именем, переданным методу. В данном случае метка была названа «css:unblock».
Метод performance.mark идет рука об руку с методом performance.measure , который используется для расчета разницы во времени между двумя отметками (в дополнение к отметкам, которые делаете вы, вы также можете использовать отметки, которые браузер автоматически делает для различных точек в Navigation Timing API ).
Следующая служебная функция измеряет и возвращает временной интервал между добавленной вами меткой и меткой responseEnd , созданной API Navigation Timing.
function measureDuration(mark, opt_reference) {
var reference = opt_reference || 'responseEnd';
var name = reference + ':' + mark;
// Clears any existing measurements with the same name.
performance.clearMeasures(name);
// Creates a new measurement from the reference point to the specified mark.
// If more than one mark with this name exists, the most recent one is used.
performance.measure(name, reference, mark);
// Gets the value of the measurement just created.
var measure = performance.getEntriesByName(name)[0];
// Returns the measure duration.
return measure.duration;
} Чтобы начать использовать эту служебную функцию, создайте новый файл с именем perf-analytics.js (в том же каталоге, что и файл index.html ), скопируйте и вставьте в него указанный выше код.
Теперь, когда эта функция определена, вы можете вызвать её и передать имя метки "css:unblock". Чтобы не мешать загрузке других ресурсов, следует отложить выполнение этих измерений до срабатывания события загрузки окна.
После того как вы напишете функцию для вызова этого кода, ваш файл perf-analytics.js должен выглядеть примерно так:
window.onload = function() {
measureCssUnblockTime();
};
/**
* Calculates the time duration between the responseEnd timing event and when
* the CSS stops blocking rendering, then logs that value to the console.
*/
function measureCssUnblockTime() {
console.log('CSS', 'unblock', measureDuration('css:unblock'));
}
/**
* Accepts a mark name and an optional reference point in the navigation timing
* API and returns the time duration between the reference point and the last
* mark (chronologically).
* @param {string} mark The mark name.
* @param {string=} opt_reference An optional reference point from the
* navigation timing API. Defaults to 'responseEnd'.
* @return {number} The time duration
*/
function measureDuration(mark, opt_reference) {
var reference = opt_reference || 'responseEnd';
var name = reference + ':' + mark;
// Clears any existing measurements with the same name.
performance.clearMeasures(name);
// Creates a new measurement from the reference point to the specified mark.
// If more than one mark with this name exists, the most recent one is used.
performance.measure(name, reference, mark);
// Gets the value of the measurement just created.
var measure = performance.getEntriesByName(name)[0];
// Returns the measure duration.
return measure.duration;
} Наконец, вам нужно загрузить скрипт perf-analytics.js из index.html . Для этого добавьте следующий тег script в основной документ. Добавьте его в последнюю очередь, чтобы он не мешал загрузке других ресурсов.
<!-- Start performance analytics -->
<script async src="perf-analytics.js"></script>
<!-- End performance analytics --> После завершения этого шага ваш код должен соответствовать коду в каталоге 01-css репозитория Code Lab.
Если вы загрузите страницу в браузере и откроете консоль разработчика, вы должны увидеть что-то вроде следующего вывода:

Веб-шрифты обычно загружаются через внешнюю таблицу стилей, как показано в исходном демонстрационном файле:
<!-- Start fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700,400italic" rel="stylesheet">
<!-- End fonts --> Поскольку это тег <link> на CSS-файл, может показаться, что определить, когда шрифты загружены и готовы к использованию, так же просто, как добавить метку внутри тега <script> сразу после <link> , как в шаге 1.
К сожалению, все не так просто.
Таблицы стилей блокируют выполнение JavaScript, поскольку их содержимое используется для построения CSSOM , и поскольку загружаемому JavaScript может потребоваться доступ к CSSOM, выполнение следует отложить до тех пор, пока CSSOM не будет полностью построен.
Загвоздка в том, что браузер может создать CSSOM без фактической загрузки шрифта. Это значит, что если вы добавите отметку с помощью встроенного тега скрипта в DOM сразу после тега <link> таблицы стилей шрифта, то, скорее всего, отметка появится до того, как шрифт будет полностью загружен.
Пока события загрузки шрифтов не станут доступны в браузерах, для определения того, когда шрифт действительно активен и готов к использованию на странице, требуется JavaScript. К счастью, загрузка шрифтов через JavaScript также обеспечивает выигрыш в производительности, поскольку не требует дополнительного блокирующего запроса к CSS-файлу.
Большинство веб-шрифтов (включая шрифты Google, Typekit и font.com) можно загрузить с помощью скрипта webfont.js , который был совместно разработан Google и Typekit.
Чтобы обновить основной документ и использовать webfont.js для загрузки шрифтов (а не тег <link>), замените раздел шрифтов в коде следующим:
<!-- Start fonts -->
<script>
window.WebFontConfig = {
google: {families: ['Roboto:400,700,400italic']},
timeout: 10000,
active: function() {
performance.mark('fonts:active');
}
};
</script>
<script async src="https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"></script>
<!-- End fonts -->В приведенном выше коде следует отметить два важных момента:
- Он создает метку «fonts:active» в активном обратном вызове, чтобы позже можно было измерить, сколько времени заняла загрузка шрифтов.
- Тег
<script>, загружающий webfonts.js, содержит атрибутasync, поэтому он не будет блокировать синтаксический анализ или рендеринг остальной части документа (что не относится к тегам<link>).
Хотя приведённый выше код создаёт метку «fonts:active», её измерение и запись в консоль не так просты, как для метки «css:unblock». Причина в том, что загрузка шрифта теперь происходит асинхронно, поэтому если вы попытаетесь измерить метку «fonts:active» в обработчике window.onload (как это было с «css:unblock»), вполне вероятно, что шрифт ещё не загружен.
Чтобы решить эту проблему, можно создать обещание, которое будет выполнено после загрузки шрифта. Следующая функция сделает это за вас. Скопируйте и вставьте её в файл perf-analytics.js:
/**
* Creates a promise that is resolved once the web fonts are fully load or
* is reject if the fonts fail to load. The resolved callback calculates the
* time duration between the responseEnd timing event and when the web fonts
* are downloaded and active. If an error occurs loading the font, this fact
* is logged to the console.
*/
function measureWebfontPerfAndFailures() {
new Promise(function(resolve, reject) {
// The classes `wf-active` or `wf-inactive` are added to the <html>
// element once the fonts are loaded (or error).
var loaded = /wf-(in)?active/.exec(document.documentElement.className);
var success = loaded && !loaded[1]; // No "in" in the capture group.
// If the fonts are already done loading, resolve immediately.
// Otherwise resolve/reject in the active/inactive callbacks, respectively.
if (loaded) {
success ? resolve() : reject();
}
else {
var originalAciveCallback = WebFontConfig.active;
WebFontConfig.inactive = reject;
WebFontConfig.active = function() {
originalAciveCallback();
resolve();
};
// In case the webfont.js script fails to load, always reject the
// promise after the timeout amount.
setTimeout(reject, WebFontConfig.timeout);
}
})
.then(function() {
console.log('Fonts', 'active', measureDuration('fonts:active'));
})
.catch(function() {
console.error('Error loading web fonts')
});
}Также обновите обработчик window.onload для вызова этой новой функции.
window.onload = function() {
measureCssUnblockTime();
measureWebfontPerfAndFailures();
};После завершения этого шага ваш код должен соответствовать тому, что находится в каталоге 02-fonts репозитория code lab.
Если вы загрузите страницу в браузере и откроете консоль разработчика, вы должны увидеть что-то вроде следующего вывода:

Определить, отображается ли изображение, не так просто, как может показаться. Из предыдущих шагов вы знаете, что таблицы стилей и синхронные теги <script> могут блокировать рендеринг, парсинг и выполнение скрипта. Однако вы, возможно, не знаете, что ни один из них не блокирует сканер предварительной загрузки браузера.
Сканер предварительной загрузки — это одна из многочисленных попыток повысить производительность, реализуемая всеми современными браузерами, даже на сайтах, не ориентированных на производительность и содержащих большое количество блокирующих ресурсов. Идея заключается в том, что, хотя некоторые ресурсы могут блокировать парсинг, рендеринг или выполнение скриптов, они не обязательно должны блокировать загрузку. Таким образом, браузер сканирует HTML-файл перед началом построения DOM и ищет ресурсы, которые можно начать загружать немедленно.
Что касается изображений, это означает, что существует высокая вероятность того, что они уже будут загружены к моменту добавления в DOM. Это также означает, что момент загрузки изображения не обязательно является хорошей метрикой производительности . Метрика производительности, которая должна вас интересовать, — это момент, когда изображение становится видимым для пользователя.
Если изображение загружено до добавления в DOM, оно становится видимым в момент появления в DOM. Если же изображение не загружено до добавления в DOM, оно становится видимым в момент срабатывания обработчика onload .
Таким образом, чтобы узнать, видно ли изображение, вам придется обрабатывать оба случая.
Это можно сделать, добавив метки в обработчик загрузки каждого изображения, а также во встроенный тег <script> сразу после последнего изображения в DOM. Идея заключается в том, что последняя метка будет отмечать момент, когда все изображения будут видны.
Чтобы добавить отметки как при загрузке изображений, так и при их отображении, обновите код изображений в index.html следующим образом:
<!-- Start images -->
<div class="gallery">
<img onload="performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/1/">
<img onload="performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/2/">
<img onload="performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/3/">
</div>
<script>performance.mark('img:visible')</script>
<!-- End images -->Поскольку метод performance.measure для конкретного имени метки всегда будет использовать последнюю метку (если он обнаружит несколько меток с одинаковым именем), для этого можно использовать служебную функцию measureDuration в файле perf-analytics.js без каких-либо дополнительных изменений:
/**
* Calculates the time duration between the responseEnd timing event and when
* all images are loaded and visible on the page, then logs that value to the
* console.
*/
function measureImagesVisibleTime() {
console.log('Images', 'visible', measureDuration('img:visible'));
}Добавьте указанную выше функцию в файл perf-analytics.js , а затем обновите обработчик window.onload для ее вызова:
window.onload = function() {
measureCssBlockTime();
measureWebfontPerfAndFailures();
measureImagesVisibleTime();
};После завершения этого шага ваш код должен соответствовать тому, что находится в каталоге 03-images репозитория code lab.
Если вы загрузите страницу в браузере и откроете консоль разработчика, вы должны увидеть что-то вроде следующего вывода:

Поскольку теги <script> без атрибута async блокируют разбор DOM до тех пор, пока они не будут загружены и выполнены, вы можете определить момент завершения выполнения всех скриптов, добавив метку во встроенный тег script сразу после последнего синхронного <script> в DOM.
Обратите внимание, что использование обработчиков onload в этом случае не сработает, поскольку браузер должен выполнить скрипт после его загрузки, а это занимает время. Скрипт, который быстро загружается, но медленно выполняется, может быть так же плох, как и скрипт с медленной загрузкой.
Чтобы отслеживать, когда весь JavaScript загружается и выполняется в основном документе, обновите раздел JavaScript в index.html следующим кодом:
<!-- Start JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>performance.mark('js:execute');</script>
<!-- End JavaScript -->Это добавит метку с именем «js:execute» сразу после загрузки и завершения выполнения скриптов для плагинов jQuery и Bootstrap.
Чтобы измерить, сколько времени это займет, добавьте следующую функцию в perf-analytics.js :
/**
* Calculates the time duration between the responseEnd timing event and when
* all synchronous JavaScript files have been downloaded and executed, then
* logs that value to the console.
*/
function measureJavaSciptExecutionTime() {
console.log('JavaScript', 'execute', measureDuration('js:execute'));
}А затем вызовите его из обработчика window.onload :
window.onload = function() {
measureCssBlockTime();
measureWebfontPerfAndFailures();
measureImagesVisibleTime();
measureJavaSciptExecutionTime();
};После завершения этого шага ваш код должен соответствовать коду в каталоге 04-javascript репозитория code lab.
Если вы загрузите страницу в браузере и откроете консоль разработчика, вы должны увидеть что-то вроде следующего вывода:

Не все браузеры поддерживают JavaScript Promise или API пользовательского времени, и если вы запустите написанный вами код в браузере без поддержки одной из этих функций, вы получите ошибки.
Чтобы решить эту проблему, можно использовать функцию обнаружения функций. Добавьте следующий фрагмент кода непосредственно перед разделом шрифтов. Эта строка JavaScript определяет поддержку метода performance.mark , поэтому её необходимо добавить на страницу до использования этого метода:
<!-- Start feature detects -->
<script>window.__perf = window.performance && performance.mark;</script>
<!-- End feature detects -->Затем в любом месте index.html , где вызывается performance.mark , добавьте к нему префикс feature detect . Вот пример, который обновляет код в блоке изображения, но вам необходимо обновить и другие разделы.
<!-- Start images -->
<div class="gallery">
<img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/1/">
<img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/2/">
<img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/3/">
</div>
<script>__perf && performance.mark('img:visible')</script>
<!-- End images -->Теперь, когда переменная __perf установлена в window , вы также можете использовать ее в perf-analytics.js чтобы убедиться, что вы не вызываете метод, который не поддерживается в текущем браузере.
Функцию measureDuration необходимо обновить, добавив следующее условие:
function measureDuration(mark, opt_reference) {
if (window.__perf) {
// ...
}
}Наконец, поскольку не все браузеры поддерживают обещания JavaScript, функция measureWebfontPerfAndFailures также должна быть заключена в условный оператор:
function measureWebfontPerfAndFailures() {
if (window.Promise) {
// ...
}
}Теперь вы сможете без проблем запустить свой код в любом браузере.
После завершения этого шага ваш код должен соответствовать коду в каталоге 05-feature-detects репозитория code lab.
Последний шаг в этой лабораторной работе — перенести данные, регистрируемые в консоли, в Google Analytics. Перед отправкой данных в Google Analytics необходимо добавить на страницу библиотеку analytics.js и фрагмент кода отслеживания по умолчанию .
Добавьте следующий код в index.html после основного блока JavaScript, но до загрузки скрипта perf-analytics.js :
<!-- Start analytics tracking snippet -->
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://www.google-analytics.com/analytics_debug.js"></script>
<!-- End analytics tracking snippet -->Если вы ранее добавляли Google Analytics на веб-сайт, вы знаете, что вам необходимо заменить заполнитель «UA-XXXXX-Y» на идентификатор отслеживания, который вы получили при создании нового ресурса в Google Analytics.
Фрагмент кода отслеживания analytics.js выполняет четыре основные функции:
- Создает асинхронный элемент
<script>, который загружает библиотеку JavaScript analytics.js. - Инициализирует глобальную функцию
ga()(называемую очередью команд ga() ), которая позволяет планировать выполнение команд после загрузки библиотеки analytics.js и ее готовности к работе. - Добавляет команду в очередь команд
ga()для создания нового объекта трекера для свойства, указанного с помощью параметра 'UA-XXXXX-Y'. - Добавляет еще одну команду в очередь команд
ga()для отправки просмотра текущей страницы в Google Analytics .
Хотя данные, собранные только по просмотрам страниц, полезны, они не отражают всей картины. Чтобы получить более полное представление о том, как пользователи взаимодействуют с вашим сайтом или приложением, необходимо отправлять дополнительные данные о взаимодействии в Google Analytics.
Google Analytics поддерживает несколько типов данных о взаимодействии: просмотры страниц , события , социальные взаимодействия , исключения и (что не менее важно) время пользователя . Чтобы отправить данные о времени пользователя в Google Analytics, можно использовать следующую сигнатуру команды:
ga('send', 'timing', timingCategory, timingVar, timingValue);Где timingCategory — это строка, позволяющая организовать временные интервалы в логическую группу, timingVar — это измеряемая переменная, а timingValue — фактическая продолжительность времени в миллисекундах.
Чтобы увидеть, как это работает на практике, оператор console.log в функции measureCssUnblockTime можно обновить следующим образом:
ga('send', 'timing', 'CSS', 'unblock', measureDuration('css:unblock'));Хотя приведенный выше код будет работать в некоторых ситуациях, есть два важных момента, о которых следует знать:
- На предыдущем шаге функция
measureDurationбыла обновлена так, чтобы она запускалась только в том случае, если браузер поддерживает API User Timings, что означает, что иногда она будет возвращатьundefined. Поскольку нет смысла отправлять неопределённые данные в Google Analytics (в некоторых случаях это может даже испортить ваши отчёты), следует отправлять этот запрос времени только в том случае, еслиmeasureDurationвозвращает значение. - Если
measureDurationвозвращает значение, оно имеет типDOMHighResTimeStampс точностью более миллисекунды. Поскольку в Google AnalyticstimingValueдолжен быть целым числом, значение, возвращаемоеmeasureDuration, необходимо округлить.
Чтобы учесть эти ошибки, обновите оператор return в функции MeasureDuration, чтобы округлить возвращаемое значение:
function measureDuration(mark, opt_reference) {
if (window.__perf) {
// ...
return Math.round(measure.duration);
}
}И обновите команды измерения времени так, чтобы они выполнялись только при наличии значения для рассматриваемой метрики. Например, функцию measureCssUnblockTime следует обновить следующим образом:
function measureCssUnblockTime() {
var cssUnblockTime = measureDuration('css:unblock');
if (cssUnblockTime) {
ga('send', 'timing', 'CSS', 'unblock', cssUnblockTime);
}
}Вам потребуется внести аналогичные изменения во все остальные функции измерения. После этого окончательный файл perf-analytics.js должен выглядеть следующим образом:
window.onload = function() {
measureCssUnblockTime();
measureWebfontPerfAndFailures();
measureImagesVisibleTime();
measureJavaSciptExecutionTime();
};
/**
* Calculates the time duration between the responseEnd timing event and when
* the CSS stops blocking rendering, then sends this measurement to Google
* Analytics via a timing hit.
*/
function measureCssUnblockTime() {
var cssUnblockTime = measureDuration('css:unblock');
if (cssUnblockTime) {
ga('send', 'timing', 'CSS', 'unblock', cssUnblockTime);
}
}
/**
* Calculates the time duration between the responseEnd timing event and when
* the web fonts are downloaded and active, then sends this measurement to
* Google Analytics via a timing hit. If an error occurs loading the font, an
* error event is sent to Google Analytics.
*/
function measureWebfontPerfAndFailures() {
if (window.Promise) {
new Promise(function(resolve, reject) {
var loaded = /wf-(in)?active/.exec(document.documentElement.className);
var success = loaded && !loaded[1]; // No "in" in the capture group.
if (loaded) {
success ? resolve() : reject();
}
else {
var originalAciveCallback = WebFontConfig.active;
WebFontConfig.inactive = reject;
WebFontConfig.active = function() {
originalAciveCallback();
resolve();
};
// In case the webfont.js script failed to load.
setTimeout(reject, WebFontConfig.timeout);
}
})
.then(function() {
var fontsActiveTime = measureDuration('fonts:active');
if (fontsActiveTime) {
ga('send', 'timing', 'Fonts', 'active', fontsActiveTime);
}
})
.catch(function() {
ga('send', 'event', 'Fonts', 'error');
});
}
}
/**
* Calculates the time duration between the responseEnd timing event and when
* all images are loaded and visible on the page, then sends this measurement
* to Google Analytics via a timing hit.
*/
function measureImagesVisibleTime() {
var imgVisibleTime = measureDuration('img:visible');
if (imgVisibleTime) {
ga('send', 'timing', 'Images', 'visible', imgVisibleTime);
}
}
/**
* Calculates the time duration between the responseEnd timing event and when
* all synchronous JavaScript files are downloaded and executed, then sends
* this measurement to Google Analytics via a timing hit.
*/
function measureJavaSciptExecutionTime() {
var jsExecuteTime = measureDuration('js:execute');
if (jsExecuteTime) {
ga('send', 'timing', 'JavaScript', 'execute', jsExecuteTime);
}
}
/**
* Accepts a mark name and an optional reference point in the navigation timing
* API and returns the time duration between the reference point and the last
* mark (chronologically). The return value is rounded to the nearest whole
* number to be compatible with Google Analytics.
* @param {string} mark The mark name.
* @param {string=} opt_reference An optional reference point from the
* navigation timing API. Defaults to 'responseEnd'.
* @return {?number} The time duration as an integer or undefined if no
* matching marks can be found.
*/
function measureDuration(mark, opt_reference) {
if (window.__perf) {
var reference = opt_reference || 'responseEnd';
var name = reference + ':' + mark;
// Clears any existing measurements with the same name.
performance.clearMeasures(name);
// Creates a new measurement from the reference point to the specified mark.
// If more than one mark with this name exists, the most recent one is used.
performance.measure(name, reference, mark);
// Gets the value of the measurement just created.
var measure = performance.getEntriesByName(name)[0];
// Returns the measure duration.
return Math.round(measure.duration);
}
}И окончательный файл index.html должен выглядеть так:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Performance Analytics Demo</title>
<!-- Start navigation timing feature detect -->
<script>window.__perf = window.performance && performance.mark;</script>
<!-- End navigation timing feature detect -->
<!-- Start fonts -->
<script>
window.WebFontConfig = {
google: {families: ['Roboto:400,700,400italic']},
timeout: 10000,
active: function() {
__perf && performance.mark('fonts:active');
}
};
</script>
<script async src="https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"></script>
<!-- End fonts -->
<!-- Start CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
<style>
body { font-family: Roboto, sans-serif; margin: 1em; }
img { float: left; height: auto; width: 33.33%; }
.gallery { overflow: hidden; }
</style>
<script>__perf && performance.mark('css:unblock');</script>
<!-- End CSS -->
</head>
<body>
<div class="container">
<!-- Start images -->
<div class="gallery">
<img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/1/">
<img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/2/">
<img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/3/">
</div>
<script>__perf && performance.mark('img:visible')</script>
<!-- End images -->
<h1>Performance Analytics Demo</h1>
<p>Real performance data from real users.</p>
</div>
<!-- Start JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>__perf && performance.mark('js:execute');</script>
<!-- End JavaScript -->
<!-- Start analytics tracking snippet -->
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>
<!-- End analytics tracking snippet -->
<!-- Start performance analytics -->
<script async src="perf-analytics.js"></script>
<!-- End performance analytics -->
</body>
</html>Если вы загрузите эту страницу и посмотрите на запросы на сетевой панели, вы увидите что-то вроде следующего:

Это полезно, но просмотр этих данных в виде URL-запроса может быть затруднительным. И если по какой-либо причине вы не видите эти запросы, очень сложно отследить, где произошёл сбой.
При локальной разработке лучше использовать отладочную версию analytics.js , которая будет выводить полезную отладочную информацию в консоль при каждом выполнении команды analytics.js. Если вы
обновите URL analytics.js в index.html на analytics_debug.js и откройте консоль браузера. Вы увидите распечатанные операторы, которые выглядят примерно так:

Теперь, когда вы понимаете, как реализовать измерение производительности для этой демонстрационной страницы, вы можете попробовать добавить ее на свой сайт, отправляя реальные данные о пользователях в Google Analytics.
Отчет о собранных вами данных
После того как вы пособираете данные об эффективности в течение нескольких дней, вы сможете составить отчет на основе этих данных, чтобы получить полезную информацию о том, насколько быстро ваш сайт и его ресурсы загружаются для реальных пользователей.
Чтобы открыть отчеты по пользовательскому времени в Google Analytics, нажмите вкладку «Отчетность» вверху и выберите «Поведение > Скорость сайта > Пользовательское время» на боковой панели навигации (или следуйте инструкциям по просмотру отчета по пользовательскому времени в Справочном центре).
При загрузке отчёта «Пользовательское время» в Google Analytics вы увидите категории времени, соответствующие отправленным вами данным. Нажмите на любую из них, чтобы увидеть подробную визуализацию данных о времени. На следующем изображении показан пример времени загрузки шрифтов на реальном сайте с использованием Google Fonts за последние 24 часа.

Поздравляем! Вы успешно завершили эту лабораторную работу по коду. Если вы хотите изучить её подробнее, в следующем разделе вы найдёте несколько советов по использованию этого кода для ещё более глубокого понимания.
Метрики производительности, рассматриваемые в этой лабораторной работе, критически важны для оценки загрузки вашего сайта для реальных пользователей, но это только начало. Если вы хотите глубже изучить аналитику производительности, следующим простым шагом будет отслеживание дополнительных метрик.
В этой лабораторной работе по кодированию вы отслеживали метрики, связанные с доступностью ресурсов пользователю. При желании большинство из них можно было бы разбить ещё на более детальные показатели. Например, вместо того, чтобы просто измерять время завершения выполнения JavaScript, вы могли бы измерять время начала загрузки, время завершения загрузки, время начала выполнения и, наконец, время завершения выполнения. Каждая из этих метрик может выявить проблему, которую не выявила бы каждая из них.
Помимо более детального анализа, вам следует также более комплексно подойти к общей стратегии аналитики эффективности. Каковы цели? Что такое успех?
Когда дело доходит до любого вида аналитики, вы обычно хотите начать с какого-то вопроса, а затем выяснить, как использовать данные, чтобы ответить на этот вопрос.
Например, рассмотрите следующий список вопросов и то, как бы вы использовали знания, полученные в этой лабораторной работе по кодированию, чтобы с помощью аналитики ответить на них:
- Уменьшаются или увеличиваются значения отслеживаемых вами показателей с течением времени?
- Как использование автономного кэширования с помощью Service Worker или локального хранилища повлияет на общую производительность вашего сайта?
- Оптимально ли загружаются ваши ресурсы? Большой ли разрыв между загрузкой ресурса и его доступностью для использования?
- Есть ли какая-либо корреляция между эффективностью и другими показателями, которые вы отслеживаете (например, скоростью регистрации, временем на сайте, покупками и т. д.)?
Наконец, если вы хотите узнать больше о веб-эффективности или Google Analytics, вот несколько отличных ресурсов, с которых можно начать:
- Инструменты и информация, которые помогут вам создавать высокопроизводительные веб-сайты
https://developers.google.com/speed/ - Инструменты и API для разработчиков, позволяющие использовать платформу Google Analytics
https://developers.google.com/analytics/ - Онлайн-курсы, на которых вас научат, как использовать сам продукт Google Analytics (преподаватели — специалисты, работающие непосредственно над Google Analytics).
https://analyticsacademy.withgoogle.com/