Измерение реального влияния на производительность сервисных работников

Одним из наиболее значительных преимуществ сервисных работников (по крайней мере, с точки зрения производительности) является их способность активно контролировать кэширование ресурсов. Веб-приложение, которое может кэшировать все необходимые ресурсы, должно загружаться значительно быстрее для постоянных посетителей. Но как эти преимущества на самом деле выглядят для реальных пользователей? И как это вообще измерить?

Веб-приложение Google I/O (сокращенно IOWA) — это прогрессивное веб-приложение , которое использовало большинство новых возможностей, предлагаемых сервисными работниками, для предоставления своим пользователям богатого опыта, подобного приложению. Компания также использовала Google Analytics для сбора ключевых данных о производительности и моделях использования своей большой и разнообразной аудитории пользователей.

В этом тематическом исследовании показано, как IOWA использовала Google Analytics, чтобы ответить на ключевые вопросы производительности и составить отчет о реальном влиянии работников сферы обслуживания.

Начиная с вопросов

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

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

1. Является ли кэширование Service Worker более производительным, чем существующие механизмы кэширования HTTP, доступные во всех браузерах?

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

Service Workers предлагает альтернативные возможности кэширования, которые дают разработчикам детальный контроль над тем, что именно и как выполняется кеширование. В IOWA мы оптимизировали реализацию сервис-воркера так, чтобы каждый ресурс кэшировался, чтобы вернувшиеся посетители могли использовать приложение полностью в автономном режиме.

Но будут ли эти усилия лучше, чем то, что браузер уже делает по умолчанию? И если да, то насколько лучше? 1

2. Как сервис-воркер влияет на загрузку сайта?

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

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

Выбор правильной метрики

Google Analytics по умолчанию отслеживает время загрузки страниц (через API синхронизации навигации ) для 1% посетителей сайта и делает эти данные доступными с помощью таких показателей, как Avg. Время загрузки страницы.

Среднее Время загрузки страницы — хороший показатель для ответа на наш первый вопрос, но не особенно хороший показатель для ответа на второй. Во-первых, событие load не обязательно соответствует моменту, когда пользователь может фактически взаимодействовать с приложением. Более того, может показаться, что два приложения с одинаковым временем загрузки загружаются по-разному. Например, сайт с заставкой или индикатором загрузки, вероятно, будет загружаться намного быстрее, чем сайт, который просто показывает пустую страницу в течение нескольких секунд.

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

Как только мы определились с вопросами, на которые хотим ответить, и определили показатели, которые будут полезны при ответе на них, пришло время внедрить Google Analytics и начать проводить измерения.

Реализация аналитики

Если вы раньше использовали Google Analytics, то вы, вероятно, знакомы с рекомендуемым фрагментом отслеживания JavaScript. Это выглядит так:

<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>

Первая строка приведенного выше кода инициализирует глобальную функцию ga() (если она еще не существует), а последняя строка асинхронно загружает библиотеку analytics.js .

Средняя часть содержит эти две строки:

ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');

Эти две команды отслеживают, какие страницы посещают люди, заходящие на ваш сайт, но не более того . Если вы хотите отслеживать дополнительные взаимодействия с пользователем, вам придется делать это самостоятельно.

Что касается IOWA, мы хотели отслеживать еще две вещи:

  • Время, прошедшее между первой загрузкой страницы и появлением пикселей на экране.
  • Независимо от того, контролирует ли сервисный работник страницу. Имея эту информацию, мы могли сегментировать наши отчеты, чтобы сравнить результаты с использованием Service Worker и без него.

Запечатлеть время первой покраски

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

Как я уже упоминал, время первой отрисовки — важный показатель для измерения, поскольку это первая точка, в которой пользователь ощущает скорость загрузки вашего сайта. Это первое впечатление, которое получают пользователи, и хорошее первое впечатление может положительно повлиять на остальную часть пользовательского опыта. 2

Чтобы получить первое значение отрисовки в браузерах, которые его предоставляют, мы создали служебную функцию getTimeToFirstPaintIfSupported :

function getTimeToFirstPaintIfSupported() {
  // Ignores browsers that don't support the Performance Timing API.
  if (window.performance && window.performance.timing) {
    var navTiming = window.performance.timing;
    var navStart = navTiming.navigationStart;
    var fpTime;

    // If chrome, get first paint time from `chrome.loadTimes`.
    if (window.chrome && window.chrome.loadTimes) {
      fpTime = window.chrome.loadTimes().firstPaintTime * 1000;
    }
    // If IE/Edge, use the prefixed `msFirstPaint` property.
    // See http://msdn.microsoft.com/ff974719
    else if (navTiming.msFirstPaint) {
      fpTime = navTiming.msFirstPaint;
    }

    if (fpTime && navStart) {
      return fpTime - navStart;
    }
  }
}

Благодаря этому мы теперь могли бы написать еще одну функцию, которая отправляет событие отсутствия взаимодействия со временем первой отрисовки в качестве значения: 3

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    ga('send', 'event', {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    });
  }
}

После написания обеих этих функций наш код отслеживания будет выглядеть следующим образом:

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sends a pageview for the initial pageload.
ga('send', 'pageview');

// Sends an event with the time to first paint data.
sendTimeToFirstPaint();

Обратите внимание, что в зависимости от того, когда выполняется приведенный выше код, пиксели могут быть уже нарисованы на экране, а могут и не быть. Чтобы гарантировать, что мы всегда запускаем этот код после первой отрисовки, мы отложили вызов sendTimeToFirstPaint() до события load . Фактически, мы решили отложить отправку всех аналитических данных до загрузки страницы, чтобы гарантировать, что эти запросы не будут конкурировать с загрузкой других ресурсов.

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

Код выше сообщает Google Analytics о времени firstpaint , но это только половина дела. Нам все еще нужно было отслеживать статус сервис-воркера; в противном случае мы не смогли бы сравнить время первой отрисовки страницы, контролируемой сервисным работником, и неконтролируемой страницы.

Определение статуса сервисного работника

Чтобы определить текущий статус сервис-воркера, мы создали служебную функцию, которая возвращает одно из трех значений:

  • контролируемый : сервисный работник контролирует страницу. В случае с IOWA это также означает, что все ресурсы кэшированы и страница работает в автономном режиме.
  • поддерживается : браузер поддерживает сервис-воркера, но сервис-воркер еще не управляет страницей. Это ожидаемый статус для посетителей, впервые посещающих сайт.
  • неподдерживаемый : браузер пользователя не поддерживает Service Worker.
function getServiceWorkerStatus() {
  if ('serviceWorker' in navigator) {
    return navigator.serviceWorker.controller ? 'controlled' : 'supported';
  } else {
    return 'unsupported';
  }
}

Эта функция получила для нас статус сервис-воркера; Следующим шагом было связать этот статус с данными, которые мы отправляли в Google Analytics.

Отслеживание пользовательских данных с помощью пользовательских параметров

По умолчанию Google Analytics предоставляет вам множество способов разделить общий трафик на группы на основе атрибутов пользователя, сеанса или взаимодействия. Эти атрибуты известны как измерения . Общие параметры, которые волнуют веб-разработчиков, — это такие вещи, как браузер , операционная система или категория устройства .

Статус сервисного работника не является параметром, который Google Analytics предоставляет по умолчанию; однако Google Analytics дает вам возможность создавать собственные параметры и определять их по своему усмотрению.

Для IOWA мы создали специальный параметр под названием «Статус Service Worker» и установили его область действия на попадание (т. е. на каждое взаимодействие). 4. Каждому специальному параметру, который вы создаете в Google Analytics, присваивается уникальный индекс внутри этого свойства, и в коде отслеживания вы можете ссылаться на этот параметр по его индексу. Например, если бы индекс только что созданного измерения был равен 1, мы могли бы обновить нашу логику следующим образом, чтобы отправить событие firstpaint , включив в него статус сервисного работника:

ga('send', 'event', {
  eventCategory: 'Performance',
  eventAction: 'firstpaint',
  // Rounds to the nearest millisecond since
  // event values in Google Analytics must be integers.
  eventValue: Math.round(timeToFirstPaint)
  // Sends this as a non-interaction event,
  // so it doesn't affect bounce rate.
  nonInteraction: true,

  // Sets the current service worker status as the value of
  // `dimension1` for this event.
  dimension1: getServiceWorkerStatus()
});

Это работает, но статус сервисного работника будет ассоциироваться только с этим конкретным событием. Поскольку статус Service Worker потенциально полезен при любом взаимодействии, лучше всего включать его во все данные, отправляемые в Google Analytics.

Чтобы включить эту информацию во все обращения (например, все просмотры страниц, события и т. д.), мы устанавливаем значение специального параметра в самом объекте отслеживания перед отправкой каких-либо данных в Google Analytics.

ga('set', 'dimension1', getServiceWorkerStatus());

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

Небольшое замечание о ясности и читаемости кода: поскольку другие люди, просматривающие этот код, могут не знать, к чему относится dimension1 , всегда лучше создать переменную, которая сопоставляет осмысленные имена измерений со значениями, которые будет использовать Analytics.js.

// Creates a map between custom dimension names and their index.
// This is particularly useful if you define lots of custom dimensions.
var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1'
};

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sets the service worker status on the tracker,
// so its value is included in all future hits.
ga('set', customDimensions.SERVICE_WORKER_STATUS, getServiceWorkerStatus());

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

Как я уже упоминал, отправка измерения «Статус Service Worker» при каждом обращении позволяет нам использовать его при составлении отчетов по любой метрике.

Как видите, почти 85% всех просмотров страниц IOWA были осуществлены из браузеров, поддерживающих Service Worker .

Результаты: отвечаем на наши вопросы

Как только мы начали собирать данные для ответа на наши вопросы, мы могли сообщить об этих данных, чтобы увидеть результаты. (Примечание: все показанные здесь данные Google Analytics представляют собой фактический веб-трафик сайта IOWA за период с 16 по 22 мая 2016 г.).

Первый вопрос, который у нас возник: является ли кэширование Service Worker более производительным, чем существующие механизмы кэширования HTTP, доступные во всех браузерах?

Чтобы ответить на этот вопрос, мы создали специальный отчет , в котором учитывается показатель Avg. Время загрузки страницы в различных измерениях. Эта метрика хорошо подходит для ответа на этот вопрос, поскольку событие load срабатывает только после загрузки всех начальных ресурсов. Таким образом, оно напрямую отражает общее время загрузки всех критически важных ресурсов сайта. 5

Размеры, которые мы выбрали:

  • Наше индивидуальное измерение «Статус сервисного работника» .
  • Тип пользователя , который указывает, является ли это первым посещением сайта пользователем или он возвращается. (Примечание: у нового посетителя не будет кэшированных ресурсов; у вернувшегося посетителя могут быть кэшированные ресурсы.)
  • Категория устройства , которая позволяет нам сравнивать результаты на мобильных устройствах и настольных компьютерах.

Чтобы исключить вероятность того, что факторы, не связанные с Service Worker, искажают результаты времени загрузки, мы ограничили наш запрос, включив в него только браузеры, поддерживающие Service Worker.

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

«…посещения нашего приложения, контролируемые сервисным работником, загружаются немного быстрее, чем неконтролируемые посещения…»

Более подробную информацию вы можете увидеть в следующих двух таблицах:

Среднее Время загрузки страницы (рабочий стол)
Статус сервисного работника Тип пользователя Среднее Время загрузки страницы (мс) Размер выборки
Контролируемый Возвращающийся посетитель 2568 30860
Поддерживается Возвращающийся посетитель 3612 1289
Поддерживается Новый посетитель 4664 21991
Среднее Время загрузки страницы (мобильное устройство)
Статус сервисного работника Тип пользователя Среднее Время загрузки страницы (мс) Размер выборки
Контролируемый Возвращающийся посетитель 3760 8162
Поддерживается Возвращающийся посетитель 4843 676
Поддерживается Новый посетитель 6158 5779

Вам может быть интересно, как это возможно, чтобы вернувшийся посетитель, чей браузер поддерживает Service Worker, когда-либо находился в неконтролируемом состоянии. Этому есть несколько возможных объяснений:

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

Обе эти ситуации относительно редки. Мы можем увидеть это в данных, посмотрев на значения образца загрузки страницы в четвертом столбце. Обратите внимание, что средние строки содержат гораздо меньшую выборку, чем две другие.

Наш второй вопрос был: как сервис-воркер влияет на загрузку сайта?

Чтобы ответить на этот вопрос, мы создали еще один специальный отчет для метрики Avg. Event Value и отфильтровал результаты, чтобы включить только наши события firstpaint . Мы использовали измерения «Категория устройства» и наше собственное измерение «Статус сервисного работника» .

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

«…Service Worker на мобильных устройствах оказал гораздо меньшее влияние на время первой отрисовки, чем на общую загрузку страницы».

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

Получение распределения метрики в Google Analytics

Чтобы получить распределение времени firstpaint , нам нужен доступ к отдельным результатам для каждого события. К сожалению, Google Analytics не упрощает эту задачу.

Google Analytics позволяет нам разбить отчет по любому измерению, которое мы хотим, но не позволяет разбивать отчет по показателям. Это не значит, что это невозможно, это просто означает, что нам пришлось еще немного настроить нашу реализацию, чтобы получить желаемый результат.

Поскольку результаты отчета можно разбить только по измерениям, нам пришлось установить значение метрики (в данном случае время firstpaint ) в качестве специального измерения для события. Для этого мы создали еще один специальный параметр под названием «Значение показателя» и обновили логику отслеживания firstpaint следующим образом:

var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1',
  <strong>METRIC_VALUE: 'dimension2'</strong>
};

// ...

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    var fields = {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    }

    <strong>// Sets the event value as a dimension to allow for breaking down the
    // results by individual metric values at reporting time.
    fields[customDimensions.METRIC_VALUE] = String(fields.eventValue);</strong>

    ga('send', 'event', fields);
  }
}

Веб-интерфейс Google Analytics в настоящее время не предоставляет возможности визуализировать распределение произвольных значений показателей, но с помощью API Google Analytics Core Reporting API и библиотеки Google Charts мы можем запросить необработанные результаты, а затем самостоятельно построить гистограмму.

Например, следующая конфигурация запроса API использовалась для получения распределения значений firstpaint на рабочем столе с помощью неконтролируемого сервисного работника.

{
  dateRanges: [{startDate: '2016-05-16', endDate: '2016-05-22'}],
  metrics: [{expression: 'ga:totalEvents'}],
  dimensions: [{name: 'ga:dimension2'}],
  dimensionFilterClauses: [
    {
      operator: 'AND',
      filters: [
        {
          dimensionName: 'ga:eventAction',
          operator: 'EXACT',
          expressions: ['firstpaint']
        },
        {
          dimensionName: 'ga:dimension1',
          operator: 'EXACT',
          expressions: ['supported']
        },
        {
          dimensionName: 'ga:deviceCategory',
          operator: 'EXACT',
          expressions: ['desktop']
        }
      ],
    }
  ],
  orderBys: [
    {
      fieldName: 'ga:dimension2',
      orderType: 'DIMENSION_AS_INTEGER'
    }
  ]
}

Этот запрос API возвращает массив значений, которые выглядят следующим образом (Примечание: это только первые пять результатов). Результаты отсортированы от меньшего к большему, поэтому в этих строках указано самое быстрое время.

Результаты ответа API (первые пять строк)
га: измерение2 ga:totalEvents
4 3
5 2
6 10
7 8
8 10

Вот что означают эти результаты на простом английском языке:

  • Было 3 события, где значение firstpaint составляло 4 мс.
  • Было 2 события, где значение firstpaint составляло 5 мс.
  • Было 10 событий, где значение firstpaint составляло 6 мс.
  • Было 8 событий, где значение firstpaint составляло 7 мс.
  • Было 10 событий, где value firstpaint составляло 8 мс.
  • и т. д.

На основании этих результатов мы можем экстраполировать значение firstpaint для каждого отдельного события и построить гистограмму распределения. Мы сделали это для каждого из выполняемых нами запросов.

Вот как выглядел дистрибутив на десктопе с неконтролируемым (но поддерживаемым) сервис-воркером:

Время до первой раскраски на рабочем столе (поддерживается)

Среднее время firstpaint для приведенного выше распределения составляет 912 мс .

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

Время до первого распределения краски на рабочем столе (контролируется)

Обратите внимание: когда сервисный работник контролировал страницу, у многих посетителей первая отрисовка происходила практически сразу, в среднем за 583 мс .

«…когда сервисный работник контролировал страницу, многие посетители почти сразу же почувствовали первую отрисовку…»

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

Пришло время первого распространения рисования на рабочем столе

В этих результатах мне показалось интересным то, что распределение с контролируемым сервис-воркером все еще имело колоколообразную кривую после первоначального всплеска. Я ожидал большого начального скачка, а затем постепенного спада, я не ожидал второго пика кривой.

Когда я выяснил, что может быть причиной этого, я узнал, что хотя сервисный работник может управлять страницей, ее поток может быть неактивным. Браузер делает это для экономии ресурсов — очевидно, вам не нужно, чтобы каждый сервис-воркер для каждого сайта, который вы когда-либо посещали, был активен и готов в любой момент. Это объясняет хвост распределения. У некоторых пользователей произошла задержка при запуске потока сервисного работника.

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

Вот как все выглядело на мобильном телефоне:

Время первого распространения рисунков на мобильных устройствах

Хотя у нас все еще было значительное увеличение времени первой покраски, хвост стал немного больше и длиннее. Вероятно, это связано с тем, что на мобильных устройствах запуск простоя рабочего потока службы занимает больше времени, чем на настольном компьютере. Это также объясняет, почему разница между средним временем firstpaint оказалась не такой большой, как я ожидал (обсуждалось выше).

«…на мобильных устройствах запуск простоя рабочего потока службы занимает больше времени, чем на настольном компьютере».

Вот разбивка этих изменений среднего времени первой отрисовки на мобильных и настольных компьютерах, сгруппированных по статусу сервисного работника:

Среднее время до первой краски (мс)
Статус сервисного работника Рабочий стол мобильный
Контролируемый 583 1634 г.
Поддерживается (не контролируется) 912 1933 год

Хотя создание этих визуализаций распределения заняло немного больше времени и усилий, чем создание специального отчета в Google Analytics, они дают нам гораздо лучшее представление о том, как работники сферы обслуживания влияют на производительность нашего сайта, чем одни только средние значения.

Другое влияние со стороны обслуживающего персонала

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

Оффлайн доступ

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

Для отправки данных в Google Analytics требуется подключение к Интернету, но не требуется, чтобы данные отправлялись в точное время, когда произошло взаимодействие. Google Analytics поддерживает отправку данных о взаимодействии постфактум, указав смещение времени (через параметр qt ).

В течение последних двух лет IOWA использовала сценарий Service Worker , который обнаруживает неудачные обращения к Google Analytics, когда пользователь находится в автономном режиме, и воспроизводит их позже с помощью параметра qt .

Чтобы отслеживать, был ли пользователь онлайн или оффлайн, мы создали настраиваемое измерение под названием Online и установили для него значение navigator.onLine , затем мы прослушивали события online и offline и соответствующим образом обновляли измерение.

И чтобы понять, насколько часто пользователь находился в автономном режиме при использовании IOWA, мы создали сегмент , ориентированный на пользователей, совершивших хотя бы одно офлайн-взаимодействие. Оказывается, это было почти 5% пользователей.

Push-уведомления

Сервисные работники позволяют пользователям соглашаться на получение push-уведомлений. В IOWA пользователи уведомлялись о начале сеанса в их расписании.

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

В IOWA мы отправляли только уведомления, связанные с персонализированным расписанием пользователя, которое могли создавать только вошедшие в систему пользователи. Это ограничило набор пользователей, которые могли получать уведомления, только вошедшими в систему пользователями (отслеживаемыми с помощью специального параметра под названием «Войти »), чьи браузеры поддерживают push-уведомления (отслеживаемые с помощью другого специального параметра под названием «Разрешение на уведомление» ).

Следующий отчет основан на метрике «Пользователи» и нашем специальном параметре «Разрешение на уведомление», сегментированном по пользователям, которые в какой-то момент вошли в систему и чьи браузеры поддерживают push-уведомления.

Приятно видеть, что более половины наших вошедших в систему пользователей решили получать push-уведомления.

Баннеры установки приложения

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

В IOWA мы отслеживали, как часто эти подсказки отображались пользователю (и были ли они приняты) с помощью следующего кода:

window.addEventListener('beforeinstallprompt', function(event) {
  // Tracks that the user saw a prompt.
  ga('send', 'event', {
    eventCategory: 'installprompt',
    eventAction: 'fired'
  });

  event.userChoice.then(function(choiceResult) {
    // Tracks the users choice.
    ga('send', 'event', {
      eventCategory: 'installprompt',
      // `choiceResult.outcome` will be 'accepted' or 'dismissed'.
      eventAction: choiceResult.outcome,
      // `choiceResult.platform` will be 'web' or 'android' if the prompt was
      // accepted, or '' if the prompt was dismissed.
      eventLabel: choiceResult.platform
    });
  });
});

Из пользователей, увидевших баннер установки приложения, около 10% решили добавить его на свой главный экран.

Возможные улучшения отслеживания (в следующий раз)

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

1. Отслеживайте больше событий, связанных с загрузкой.

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

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

2. Сохраните идентификатор аналитического клиента в IndexedDB.

По умолчанию Analytics.js сохраняет поле идентификатора клиента в файлах cookie браузера; к сожалению, сценарии сервисных работников не могут получить доступ к файлам cookie.

Это представляло для нас проблему, когда мы пытались реализовать отслеживание уведомлений. Мы хотели отправлять событие от сервисного работника (через протокол измерений ) каждый раз, когда пользователю отправляется уведомление, а затем отслеживать успешность повторного взаимодействия с этим уведомлением, если пользователь нажмет на него и вернется в приложение.

Хотя мы могли отслеживать успех уведомлений в целом с помощью параметра кампании utm_source , мы не смогли привязать конкретный сеанс повторного вовлечения к конкретному пользователю.

Чтобы обойти это ограничение, мы могли бы сохранить идентификатор клиента через IndexedDB в нашем коде отслеживания, и тогда это значение было бы доступно сценарию сервисного работника.

3. Пусть сервисный работник сообщит о статусе онлайн/офлайн.

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

В будущем нам следует отслеживать как статус navigator.onLine , так и то, было ли обращение воспроизведено сервис-воркером из-за первоначального сбоя сети. Это даст нам более точную картину реального использования в автономном режиме.

Подведение итогов

Этот практический пример показал, что использование Service Worker действительно улучшило производительность загрузки веб-приложения Google I/O в широком диапазоне браузеров, сетей и устройств. Оно также показало, что, если вы посмотрите на распределение данных о нагрузке по широкому спектру браузеров, сетей и устройств, вы получите гораздо больше понимания того, как эта технология обрабатывает реальные сценарии, и обнаружите характеристики производительности, которых вы, возможно, не ожидали.

Вот некоторые ключевые выводы исследования IOWA:

  • В среднем страницы загружались немного быстрее, когда ими управлял сервис-воркер, чем без него, как для новых, так и для вернувшихся посетителей.
  • Посещения страниц, контролируемых сервисным работником, для многих пользователей загружались практически мгновенно.
  • Работникам службы, когда они неактивны, требуется некоторое время для запуска. Тем не менее, неактивный сервисный работник по-прежнему работал лучше, чем отсутствие сервисного работника.
  • Время запуска неактивного сервис-воркера на мобильных устройствах было больше, чем на настольных компьютерах.

Хотя о приросте производительности, наблюдаемом в одном конкретном приложении, обычно полезно сообщать более широкому сообществу разработчиков, важно помнить, что эти результаты специфичны для типа сайта IOWA (сайт мероприятия) и типа аудитории IOWA (в основном разработчики).

Если вы реализуете Service Worker в своем приложении, важно реализовать собственную стратегию измерения, чтобы вы могли оценить свою производительность и предотвратить будущий регресс. Если да, поделитесь своими результатами, чтобы каждый мог получить пользу!

Сноски

  1. Не совсем справедливо сравнивать производительность нашей реализации кэша Service Worker с производительностью нашего сайта только с HTTP-кешем. Поскольку мы оптимизировали IOWA для сервис-воркера, мы не потратили много времени на оптимизацию HTTP-кэша. Если бы мы это сделали, результаты, вероятно, были бы другими. Чтобы узнать больше об оптимизации вашего сайта для кэша HTTP, прочитайте «Эффективная оптимизация контента» .
  2. В зависимости от того, как ваш сайт загружает стили и контент, возможно, браузер сможет рисовать до того, как контент или стили станут доступны. В таких случаях firstpaint может соответствовать пустому белому экрану. Если вы используете firstpaint , важно убедиться, что он соответствует значимому моменту загрузки ресурсов вашего сайта.
  3. Технически мы могли бы отправить временной удар (который по умолчанию не является взаимодействием), чтобы захватить эту информацию вместо события. Фактически, временные попадания были добавлены в Google Analytics специально для отслеживания таких показателей нагрузки; однако совпадения по времени подвергаются тщательной выборке во время обработки, и их значения не могут использоваться в сегментах . Учитывая эти текущие ограничения, события без взаимодействия остаются более подходящими.
  4. Чтобы лучше понять, какую область действия следует предоставить специальному параметру в Google Analytics, обратитесь к разделу «Пользовательский параметр» Справочного центра Google Analytics. Также важно понимать модель данных Google Analytics, которая состоит из пользователей, сеансов и взаимодействий (обращений). Чтобы узнать больше, посмотрите урок Analytics Academy, посвященный модели данных Google Analytics .
  5. Это не учитывает ресурсы, лениво загружаемые после события загрузки.
,

Одним из наиболее значительных преимуществ сервисных работников (по крайней мере, с точки зрения производительности) является их способность активно контролировать кэширование ресурсов. Веб-приложение, которое может кэшировать все необходимые ресурсы, должно загружаться значительно быстрее для постоянных посетителей. Но как эти преимущества на самом деле выглядят для реальных пользователей? И как это вообще измерить?

Веб-приложение Google I/O (сокращенно IOWA) — это прогрессивное веб-приложение , которое использовало большинство новых возможностей, предлагаемых сервисными работниками, для предоставления своим пользователям богатого опыта, подобного приложению. Компания также использовала Google Analytics для сбора ключевых данных о производительности и моделях использования своей большой и разнообразной аудитории пользователей.

В этом тематическом исследовании показано, как IOWA использовала Google Analytics, чтобы ответить на ключевые вопросы производительности и составить отчет о реальном влиянии работников сферы обслуживания.

Начиная с вопросов

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

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

1. Является ли кэширование Service Worker более производительным, чем существующие механизмы кэширования HTTP, доступные во всех браузерах?

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

Service Workers предлагает альтернативные возможности кэширования, которые дают разработчикам детальный контроль над тем, что именно и как выполняется кеширование. В IOWA мы оптимизировали реализацию сервис-воркера так, чтобы каждый ресурс кэшировался, чтобы вернувшиеся посетители могли использовать приложение полностью в автономном режиме.

Но будут ли эти усилия лучше, чем то, что браузер уже делает по умолчанию? И если да, то насколько лучше? 1

2. Как сервис-воркер влияет на загрузку сайта?

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

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

Выбор правильной метрики

Google Analytics по умолчанию отслеживает время загрузки страниц (через API синхронизации навигации ) для 1% посетителей сайта и делает эти данные доступными с помощью таких показателей, как Avg. Время загрузки страницы.

Среднее Время загрузки страницы — хороший показатель для ответа на наш первый вопрос, но не особенно хороший показатель для ответа на второй. Во-первых, событие load не обязательно соответствует моменту, когда пользователь может фактически взаимодействовать с приложением. Более того, может показаться, что два приложения с одинаковым временем загрузки загружаются по-разному. Например, сайт с заставкой или индикатором загрузки, вероятно, будет загружаться намного быстрее, чем сайт, который просто показывает пустую страницу в течение нескольких секунд.

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

Как только мы определились с вопросами, на которые хотим ответить, и определили показатели, которые будут полезны при ответе на них, пришло время внедрить Google Analytics и начать проводить измерения.

Реализация аналитики

Если вы раньше использовали Google Analytics, то вы, вероятно, знакомы с рекомендуемым фрагментом отслеживания JavaScript. Это выглядит так:

<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>

Первая строка приведенного выше кода инициализирует глобальную функцию ga() (если она еще не существует), а последняя строка асинхронно загружает библиотеку analytics.js .

Средняя часть содержит эти две строки:

ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');

Эти две команды отслеживают, какие страницы посещают люди, заходящие на ваш сайт, но не более того . Если вы хотите отслеживать дополнительные взаимодействия с пользователем, вам придется делать это самостоятельно.

Что касается IOWA, мы хотели отслеживать еще две вещи:

  • Время, прошедшее между первой загрузкой страницы и появлением пикселей на экране.
  • Независимо от того, контролирует ли сервисный работник страницу. Имея эту информацию, мы могли сегментировать наши отчеты, чтобы сравнить результаты с использованием Service Worker и без него.

Запечатлеть время первой покраски

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

Как я уже упоминал, время для первой краски является важной метрикой для измерения, потому что это первая точка, в которой пользователь испытывает скорость нагрузки вашего сайта. Это первое впечатление, которое получают пользователи, и хорошее первое впечатление может положительно повлиять на остальную часть пользовательского опыта. 2

Чтобы получить первое значение краски в браузерах, которые ее выявляют, мы создали функцию getTimeToFirstPaintIfSupported Cotility:

function getTimeToFirstPaintIfSupported() {
  // Ignores browsers that don't support the Performance Timing API.
  if (window.performance && window.performance.timing) {
    var navTiming = window.performance.timing;
    var navStart = navTiming.navigationStart;
    var fpTime;

    // If chrome, get first paint time from `chrome.loadTimes`.
    if (window.chrome && window.chrome.loadTimes) {
      fpTime = window.chrome.loadTimes().firstPaintTime * 1000;
    }
    // If IE/Edge, use the prefixed `msFirstPaint` property.
    // See http://msdn.microsoft.com/ff974719
    else if (navTiming.msFirstPaint) {
      fpTime = navTiming.msFirstPaint;
    }

    if (fpTime && navStart) {
      return fpTime - navStart;
    }
  }
}

При этом мы теперь могли бы написать еще одну функцию, которая посылает событие , не связанное с Interaction, со временем для первой краски в качестве его значения: 3

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    ga('send', 'event', {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    });
  }
}

После написания обе эти функции наш код отслеживания выглядит следующим образом:

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sends a pageview for the initial pageload.
ga('send', 'pageview');

// Sends an event with the time to first paint data.
sendTimeToFirstPaint();

Обратите внимание, что в зависимости от того, когда запускается вышеуказанный код, пиксели могли или не могут быть окрашены на экран. Чтобы убедиться, что мы всегда запускаем этот код после того, как произойдет первая краска, мы отложили вызов, чтобы sendTimeToFirstPaint() до события load . Фактически, мы решили отложить отправку всех аналитических данных до тех пор, пока страница не будет загружена, чтобы эти запросы не будут конкурировать с загрузкой других ресурсов.

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

Приведенный выше код сообщает firstpaint Times для Google Analytics, но это только половина истории. Нам все еще нужно было отслеживать статус обслуживающего работника; В противном случае мы не сможем сравнить первое время краски страницы, контролируемой обслуживанием, и неконтролируемой страницы.

Определение статуса работника обслуживания

Чтобы определить текущее состояние работника службы, мы создали функцию утилиты, которая возвращает одно из трех значений:

  • Контролируемый : обслуживающий работник контролирует страницу. В случае с Айовой, это также означает, что все активы были кэшированы, а страница работает в автономном режиме.
  • Поддерживается : браузер поддерживает обслуживающего работника, но обслуживающий работник еще не контролирует страницу. Это ожидаемый статус для первых посетителей.
  • Не поддерживается : браузер пользователя не поддерживает работника службы.
function getServiceWorkerStatus() {
  if ('serviceWorker' in navigator) {
    return navigator.serviceWorker.controller ? 'controlled' : 'supported';
  } else {
    return 'unsupported';
  }
}

Эта функция получила статус работника службы для нас; Следующим шагом было связать этот статус с данными, которые мы отправляли в Google Analytics.

Отслеживание пользовательских данных с пользовательскими измерениями

По умолчанию Google Analytics предоставляет вам много способов подразделения вашего общего трафика на группы на основе атрибутов пользователя, сеанса или взаимодействия. Эти атрибуты известны как измерения . Занятые разработчиками общих аспектов заботятся такие вещи, как браузер , операционная система или категория устройств .

Статус работника службы не является измерением Google Analytics предоставляет по умолчанию; Тем не менее, Google Analytics дает вам возможность создавать свои собственные пользовательские измерения и определять их так, как хотите.

Для Айовы мы создали пользовательское измерение под названием «Служба работника» и установили его применение (т.е. для перемещения). 4 Каждому пользовательскому измерению, которое вы создаете в Google Analytics, предоставляется уникальный индекс в этом свойстве, и в вашем коде отслеживания вы можете ссылаться на это измерение по его индексу. Например, если индекс измерения, который мы только что создали, был 1, мы могли бы обновить нашу логику следующим образом, чтобы отправить событие firstpaint , чтобы включить статус работника службы:

ga('send', 'event', {
  eventCategory: 'Performance',
  eventAction: 'firstpaint',
  // Rounds to the nearest millisecond since
  // event values in Google Analytics must be integers.
  eventValue: Math.round(timeToFirstPaint)
  // Sends this as a non-interaction event,
  // so it doesn't affect bounce rate.
  nonInteraction: true,

  // Sets the current service worker status as the value of
  // `dimension1` for this event.
  dimension1: getServiceWorkerStatus()
});

Это работает, но это будет связывать статус работника службы с этим конкретным событием. Поскольку статус работника службы является чем -то полезным для любого взаимодействия, лучше всего включить его со всеми данными, отправленными в Google Analytics.

Чтобы включить эту информацию во все хиты (например, все просмотры страниц, события и т. Д.) Мы устанавливаем пользовательское значение измерения в самом объекте Tracker , перед отправкой любых данных в Google Analytics.

ga('set', 'dimension1', getServiceWorkerStatus());

После установки это значение отправляется со всеми последующими ударами для текущей промежуточной загрузки. Если пользователь снова загрузит страницу позже, новое значение, вероятно, будет возвращено из функции getServiceWorkerStatus() , и это значение будет установлено на объекте Tracker.

Краткое примечание о ясности кода и читабельности: поскольку другие люди, смотрящие на этот код, могут не знать, что относится dimension1 , всегда лучше создавать переменную, которая отображает значимые имена измерений для значений Analytics.js.

// Creates a map between custom dimension names and their index.
// This is particularly useful if you define lots of custom dimensions.
var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1'
};

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sets the service worker status on the tracker,
// so its value is included in all future hits.
ga('set', customDimensions.SERVICE_WORKER_STATUS, getServiceWorkerStatus());

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

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

Как вы можете видеть почти 85% всех просмотров страниц для Айовы, были из браузеров, которые поддерживают работника службы .

Результаты: отвечать на наши вопросы

Как только мы начали собирать данные, чтобы ответить на наши вопросы, мы могли бы сообщить об этих данных, чтобы увидеть результаты. (Примечание. Все данные Google Analytics, показанные здесь, представляют фактический веб-трафик на сайте Айовы с 16-22 мая 2016 года).

Первый вопрос, который у нас был, заключался в том, более ли обслуживание кэширует кэширование, чем существующие механизмы кэширования HTTP, доступные во всех браузерах?

Чтобы ответить на этот вопрос, мы создали пользовательский отчет , который рассмотрел метрическую AVG. Время загрузки страницы в различных измерениях. Этот показатель хорошо подходит для ответа на этот вопрос, потому что событие load запускается только после того, как загружаются все начальные ресурсы. Таким образом, он напрямую отражает общее время загрузки для всех критических ресурсов сайта. 5

Измерения, которые мы выбрали, были:

  • Наше измерение статуса статуса обслуживания .
  • Тип пользователя , который указывает, является ли это первым посещением пользователя на сайт или возвращается. (Примечание: у нового посетителя не будет кэширования ресурсов; возвращающийся посетитель может.)
  • Категория устройства , которая позволяет нам сравнивать результаты по мобильному и настольному столу.

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

Как вы можете видеть, посещения нашего приложения при управлении работником службы загружались немного быстрее, чем неконтролируемые визиты, даже тех, от возвращающихся пользователей, которые, вероятно, имели большую часть ресурсов страницы. Также интересно заметить, что в среднем посетители на мобильном телефоне с сервисным работником видели быстрее, чем новые посетители настольных компьютеров.

«… Посещение нашего приложения, когда контролируется работником службы, загруженным немного быстрее, чем неконтролируемые визиты…»

Вы можете увидеть более подробную информацию в следующих двух таблицах:

Среднее Страница время загрузки (настольный компьютер)
Статус работника обслуживания Тип пользователя Среднее Страница время загрузки (MS) Размер выборки
Контролируемый Возвращающийся посетитель 2568 30860
Поддерживается Возвращающийся посетитель 3612 1289
Поддерживается Новый посетитель 4664 21991
Среднее Страница время загрузки (мобильный)
Статус работника обслуживания Тип пользователя Среднее Страница время загрузки (MS) Размер выборки
Контролируемый Возвращающийся посетитель 3760 8162
Поддерживается Возвращающийся посетитель 4843 676
Поддерживается Новый посетитель 6158 5779

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

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

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

Наш второй вопрос был: как обслуживающий работник влияет на опыт загрузки сайта?

Чтобы ответить на этот вопрос, мы создали еще один пользовательский отчет для метрического AVG. Значение события и отфильтровало результаты, чтобы включить только наши события firstpaint . Мы использовали категорию устройства Dimensions и наше пользовательское измерение статуса работника службы .

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

«… Сервисный работник на Mobile оказал гораздо меньшее влияние на время первой краски, чем на общей загрузке страницы».

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

Получение распространения метрики в Google Analytics

Чтобы получить распределение времени firstpaint , нам нужен доступ к отдельным результатам для каждого события. К сожалению, Google Analytics не облегчает это.

Google Analytics позволяет нам разбить отчет по любым измерению, которое мы хотим, но не позволяет использовать отчет по метрикам. Это не значит, что это невозможно, это просто означает, что мы должны были настроить нашу реализацию немного больше, чтобы получить желаемый результат.

Поскольку результаты отчета могут быть разбиты только из -за размеров, нам пришлось установить значение метрического значения (в данном случае firstpaint время) в качестве пользовательского измерения на событии. Для этого мы создали еще одно пользовательское измерение, называемое метрическим значением и обновили нашу логику отслеживания firstpaint следующим образом:

var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1',
  <strong>METRIC_VALUE: 'dimension2'</strong>
};

// ...

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    var fields = {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    }

    <strong>// Sets the event value as a dimension to allow for breaking down the
    // results by individual metric values at reporting time.
    fields[customDimensions.METRIC_VALUE] = String(fields.eventValue);</strong>

    ga('send', 'event', fields);
  }
}

В настоящее время веб -интерфейс Google Analytics в настоящее время не предоставляет способ визуализации распределения произвольных показателей метрических значений, но с помощью API отчетности Google Analytics Core Reporting и библиотеки Google, которые мы могли бы запросить необработанные результаты, а затем построить гистограмму сами.

Например, следующая конфигурация запроса API была использована для получения распределения значений firstpaint на рабочем столе с неконтролируемым работником службы.

{
  dateRanges: [{startDate: '2016-05-16', endDate: '2016-05-22'}],
  metrics: [{expression: 'ga:totalEvents'}],
  dimensions: [{name: 'ga:dimension2'}],
  dimensionFilterClauses: [
    {
      operator: 'AND',
      filters: [
        {
          dimensionName: 'ga:eventAction',
          operator: 'EXACT',
          expressions: ['firstpaint']
        },
        {
          dimensionName: 'ga:dimension1',
          operator: 'EXACT',
          expressions: ['supported']
        },
        {
          dimensionName: 'ga:deviceCategory',
          operator: 'EXACT',
          expressions: ['desktop']
        }
      ],
    }
  ],
  orderBys: [
    {
      fieldName: 'ga:dimension2',
      orderType: 'DIMENSION_AS_INTEGER'
    }
  ]
}

Этот запрос API возвращает массив значений, которые выглядят так (примечание: это только первые пять результатов). Результаты сортируются от наименьшего до самого большого, поэтому эти ряды представляют самые быстрые времена.

Результаты ответа API (первые пять рядов)
GA: Dimension2 GA: Тоталевенты
4 3
5 2
6 10
7 8
8 10

Вот что означают эти результаты на простом английском:

  • Было 3 события, где значение firstpaint составляло 4 мс.
  • Было 2 события, где значение firstpaint составляло 5 мс.
  • Было 10 событий, где значение firstpaint составляло 6 мс
  • Было 8 событий, где значение firstpaint составляло 7 мс.
  • Было 10 событий, где value firstpaint составляло 8 мс.
  • и т. д.

Из этих результатов мы можем экстраполировать значение firstpaint для каждого отдельного события и создать гистограмму распределения. Мы сделали это для каждого из запросов, которые мы запустили.

Вот как выглядело распространение на рабочем столе с неконтролируемым (но поддерживаемым) обслуживающим работником:

Время до первого распределения краски на рабочем столе (поддерживается)

Среднее время firstpaint для вышеуказанного распределения составляет 912 мс .

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

Время до первого распределения краски на рабочем столе (контролируется)

Обратите внимание, что когда работник обслуживания контролировал страницу, многие посетители испытали почти имплайтную первую краску со средним уровнем 583 мс .

«… Когда обслуживающий работник контролировал страницу, многие посетители испытали почти первую краску почти имплайт…»

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

Время первого распределения краски на рабочем столе

Одна вещь, которую я нашел интересным в этих результатах, заключалась в том, что распределение с контролируемым работником по обслуживанию все еще имела кривую в форме колокольчика после первоначального всплеска. Я ожидал большого начального всплеска, а затем постепенного пути, я не ожидал второй пик кривой.

Когда я изучал, что может вызвать это, я узнал, что, хотя обслуживающий работник может контролировать страницу, ее поток может быть неактивным. Браузер делает это, чтобы сохранить ресурсы - очевидно, вам не нужен каждый работник службы для каждого сайта, который вы когда -либо посещали, чтобы быть активным и готовым в любой момент. Это объясняет хвост распределения. Для некоторых пользователей была задержка, в то время как зачатая тема службы работника.

Как вы можете видеть из распределения, даже с этой первоначальной задержкой, браузеры с работником службы доставляли контент быстрее, чем браузеры, проходящие через сеть.

Вот как все выглядело на мобильном:

Время первого распределения краски на мобильных

В то время как у нас все еще было значительное увеличение почти иммедиального времени первой краски, хвост был немного больше и длиннее. Вероятно, это связано с тем, что на мобильном телефоне запуск потока работника простоя встал больше, чем на рабочем столе. Это также объясняет, почему разница между средним временем firstpaint не была такой большой, как я ожидал (обсуждается выше).

«… На мобильном телефоне запуск потока простоя обслуживающего работника занимает больше времени, чем на рабочем столе».

Вот разрушение этих вариантов медианного первого времени краски на мобильных и настольных компьютерах, сгруппированных по статусу обслуживающего работника:

Среднее время до первой краски (MS)
Статус работника обслуживания Рабочий стол мобильный
Контролируемый 583 1634 г.
Поддерживается (не контролируется) 912 1933 год

В то время как создание этих визуализаций распределения потребовалось немного больше времени и усилий, чем создание пользовательского отчета в Google Analytics, они дают нам гораздо лучшее представление о том, как работники обслуживания влияют на производительность нашего сайта, чем только средние значения.

Другое влияние работников обслуживания

В дополнение к влиянию на производительность, работники обслуживания также влияют на пользовательский опыт несколькими другими способами, которые измеримы с помощью Google Analytics.

Автономный доступ

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

Отправка данных в Google Analytics требует подключения к Интернету, но это не требует, чтобы данные отправлялись в то время, когда имело место взаимодействие. Google Analytics поддерживает отправку данных взаимодействия после факта, указав смещение времени (через параметр qt ).

В течение последних двух лет Айова использовала скрипт работника службы , который обнаруживает неудачные хиты для Google Analytics, когда пользователь оказывается в автономном режиме, а позже воспроизводит их с помощью параметра qt .

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

И чтобы понять, насколько распространенным было то, что пользователь был в автономном режиме во время использования Айовы, мы создали сегмент , который нацелен на пользователей, по крайней мере, одно автономное взаимодействие. Оказывается, это было почти 5% пользователей.

Push-уведомления

Сервисные работники позволяют пользователям выбирать уведомления о Push. В Айове пользователи были уведомлены, когда начался сеанс в их расписании.

Как и в случае любой формы уведомлений, важно найти баланс между предоставлением значения пользователю и раздражающим их. Чтобы лучше понять, что происходит, важно отслеживать, выбирают ли пользователи получать эти уведомления, если они взаимодействуют с ними, когда они прибывают, и если какие-либо пользователи, которые ранее выбрали свои предпочтения и отказа.

В Айове мы отправили только уведомления, связанные с персонализированным графиком пользователя, что могут создать только пользователи, которые могут создать только пользователи. Это ограничивало набор пользователей, которые могли бы получать уведомления для регистрации пользователей (отслеживаемых через пользовательское измерение, называемое подписанным ), чьи браузеры поддерживали Push-уведомления (отслеживаемые через другое пользовательское измерение, называемое разрешением уведомления ).

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

Приятно видеть, что более половины наших подписанных пользователей решили получить Push-уведомления.

Приложение установить баннеры

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

В Айове мы отслеживали, как часто эти подсказки были показаны пользователю (и были ли они приняты) со следующим кодом:

window.addEventListener('beforeinstallprompt', function(event) {
  // Tracks that the user saw a prompt.
  ga('send', 'event', {
    eventCategory: 'installprompt',
    eventAction: 'fired'
  });

  event.userChoice.then(function(choiceResult) {
    // Tracks the users choice.
    ga('send', 'event', {
      eventCategory: 'installprompt',
      // `choiceResult.outcome` will be 'accepted' or 'dismissed'.
      eventAction: choiceResult.outcome,
      // `choiceResult.platform` will be 'web' or 'android' if the prompt was
      // accepted, or '' if the prompt was dismissed.
      eventLabel: choiceResult.platform
    });
  });
});

Из пользователей, которые видели приложение установить баннер, около 10% решили добавить его на свой домашний экран.

Возможные улучшения отслеживания (в следующий раз)

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

1. Отслеживайте больше событий, связанных с опытом нагрузки

Мы отслеживали несколько событий, которые соответствуют технической метрике (например, Htmlimportsloded , Webcomponentsready и т. Д.), Но так как большая часть нагрузки была сделана асинхронно, точка, в которой эти события снимались, не обязательно соответствовала определенному моменту в общем опыте нагрузки.

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

2. Храните идентификатор клиента Analytics в IndexedDB

По умолчанию аналитика . К сожалению, сценарии обслуживания работников не могут получить доступ к файлам cookie.

Это представило нам проблему, когда мы попытались реализовать отслеживание уведомлений. Мы хотели отправлять мероприятие от работника службы (через протокол измерения ) каждый раз, когда уведомление было отправлено пользователю, а затем отслеживать успех повторного введения этого уведомления, если пользователь нажал на него и вернулся в приложение.

Хотя мы смогли отслеживать успех уведомлений в целом через параметр кампании utm_source , мы не смогли связать конкретный сеанс повторного управления с конкретным пользователем.

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

3. Пусть работник службы отчет о онлайн/статус офлайн

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

В будущем мы должны отслеживать как статус navigator.onLine , так и в том, был ли хит -переизменен работником службы из -за первоначального сбоя сети. Это даст нам более точную картину истинного автономного использования.

Подведение итогов

Это тематическое исследование показало, что использование обслуживающего работника действительно улучшила производительность нагрузки веб -приложения Google ввода -вывода в широком спектре браузеров, сетей и устройств. Он также показал, что когда вы смотрите на распределение данных нагрузки по широкому диапазону браузеров, сетей и устройств, вы получаете гораздо большее понимание того, как эта технология обрабатывает реальные сценарии, и вы обнаруживаете характеристики производительности, которые вы, возможно, не ожидали.

Вот некоторые из ключевых выводов из исследования Айовы:

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

Хотя повышение производительности, наблюдаемые в одном конкретном приложении, в целом полезны для отчетности крупному сообществу разработчиков, важно помнить, что эти результаты специфичны для типа сайта Айова (сайт события), а тип аудитории есть (в основном разработчики).

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

Сноски

  1. Не совсем справедливо сравнить производительность нашей реализации кэша нашего обслуживания с производительностью нашего сайта с только HTTP Cache. Поскольку мы оптимизировали Айову для обслуживающего работника, мы не тратили много времени на оптимизацию для HTTP Cache. Если бы мы имели, результаты, вероятно, были бы разными. Чтобы узнать больше об оптимизации вашего сайта для кэша HTTP, эффективно прочитайте оптимизация контента .
  2. В зависимости от того, как ваш сайт загружает свои стили и контент, возможно, что браузер может рисовать до того, как будет доступен контент или стили. В таких случаях firstpaint может соответствовать чистому белому экрану. Если вы используете firstpaint , важно убедиться, что он соответствует значимой точке загрузки ресурсов вашего сайта.
  3. Технически мы могли бы отправить хит времени (который по умолчанию не внедрена), чтобы захватить эту информацию вместо события. Фактически, в Google Analytics были добавлены хиты с времени для отслеживания таких метрик загрузки, как это; Тем не менее, поражения времени пробираются во время обработки, и их значения не могут использоваться в сегментах . Учитывая эти текущие ограничения, события, не связанные с взаимодействием, остаются лучше подходящими.
  4. Чтобы лучше понять, какую область придает пользовательское измерение в Google Analytics, обратитесь к разделу пользовательского измерения справочного центра аналитики. Также важно понять модель данных Google Analytics, которая состоит из пользователей, сеансов и взаимодействий (хиты). Чтобы узнать больше, посмотрите урок Академии аналитики по модели данных Google Analytics .
  5. Это не учитывает ресурсы, лениво загруженные после события загрузки.