На пути к лучшей метрике реагирования

Узнайте о наших мыслях по измерению оперативности и поделитесь с нами своим мнением.

Энни Салливан
Annie Sullivan
Хунбо Сонг
Hongbo Song
Николас Пенья Морено
Nicolás Peña Moreno

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

В этом посте будут рассмотрены две основные темы:

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

Что такое задержка первого ввода?

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

  • click
  • keydown
  • mousedown
  • pointerdown (только если за ним следует pointerup )

Следующая диаграмма иллюстрирует FID:

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

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

Почему мы выбрали ФИД?

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

Другие показатели, такие как общее время блокировки (TBT) и время взаимодействия (TTI), основаны на длительных задачах и, как и FID, также измеряют время блокировки основного потока во время загрузки. Поскольку эти показатели можно измерить как в полевых условиях, так и в лаборатории, многие разработчики задаются вопросом, почему мы не предпочитаем один из них FID.

Для этого есть несколько причин. Возможно, самая важная причина заключается в том, что эти метрики не измеряют взаимодействие с пользователем напрямую. Все эти показатели измеряют, сколько JavaScript выполняется на странице. Хотя длительная работа JavaScript обычно вызывает проблемы на сайтах, эти задачи не обязательно влияют на взаимодействие с пользователем, если пользователь не взаимодействует со страницей во время их выполнения. Страница может иметь высокие оценки по TBT и TTI, но казаться медленной, или же она может иметь низкую оценку, но при этом быть быстрой для пользователей. По нашему опыту, эти косвенные измерения приводят к показателям, которые отлично работают для некоторых сайтов, но не для большинства сайтов. Короче говоря, тот факт, что длинные задачи и TTI не ориентированы на пользователя, делает этих кандидатов более слабыми.

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

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

Какие улучшения мы рассматриваем?

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

Мы хотим, чтобы новый показатель:

  1. Учитывайте отзывчивость всех пользовательских действий (а не только первого).
  2. Захватывайте полную продолжительность каждого события (а не только задержку).
  3. Сгруппируйте вместе события, которые происходят как часть одного и того же логического взаимодействия с пользователем, и определите задержку этого взаимодействия как максимальную продолжительность всех его событий.
  4. Создайте совокупную оценку для всех взаимодействий, происходящих на странице, на протяжении всего ее жизненного цикла.

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

Захватите полную продолжительность мероприятия

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

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

Пять шагов жизненного цикла мероприятия

Ниже приведены шаги, которые Chrome предпринимает для обработки ввода:

  1. Происходит ввод данных от пользователя. Время, в которое это происходит, является timeStamp события.
  2. Браузер выполняет проверку попадания, чтобы решить, какому фрейму HTML (основному фрейму или iframe) принадлежит событие. Затем браузер отправляет событие соответствующему процессу рендеринга, отвечающему за этот HTML-фрейм.
  3. Средство визуализации получает событие и ставит его в очередь, чтобы обработать его, когда оно станет доступным.
  4. Средство визуализации обрабатывает событие, запуская его обработчики. Эти обработчики могут ставить в очередь дополнительную асинхронную работу, такую ​​как setTimeout и выборки, которые являются частью обработки ввода. Но на этом синхронная работа завершена.
  5. На экране отображается кадр, отражающий результат работы обработчиков событий. Обратите внимание, что любые асинхронные задачи, поставленные в очередь обработчиками событий, могут оставаться незавершенными.

Время между шагами (1) и (3), указанными выше, представляет собой задержку события, которую измеряет FID.

Время между шагами (1) и (5) выше — это продолжительность события. Именно это и будет измерять наша новая метрика.

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

В идеале нам бы хотелось также зафиксировать асинхронную работу, вызванную этим событием. Но проблема в том, что правильно определить асинхронную работу, вызванную событием, чрезвычайно сложно. Например, разработчик может выбрать запуск анимации в обработчиках событий и использовать setTimeout для запуска такой анимации. Если бы мы захватили все задачи, размещенные в обработчиках, анимация задержала бы время завершения до тех пор, пока выполняется анимация. Мы считаем, что стоит изучить варианты использования эвристики для захвата асинхронной работы, которую следует выполнить как можно скорее. Однако мы хотим быть очень осторожными при этом, потому что мы не хотим наказывать работу, выполнение которой должно занять много времени. Таким образом, в наших первоначальных усилиях шаг 5 будет рассматриваться как конечная точка: он будет учитывать только синхронную работу и количество времени, необходимое для рисования после завершения такой работы. То есть мы не собираемся применять эвристику, чтобы угадать работу, которая будет запущена асинхронно на шаге 4 в нашей первоначальной попытке.

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

Группируйте события во взаимодействия

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

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

Типы взаимодействия

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

Взаимодействие Начало/окончание События рабочего стола Мобильные мероприятия
Клавиатура Клавиша нажата keydown keydown
keypress keypress
Ключ выпущен keyup keyup
Коснитесь или перетащите Нажмите «Старт» или перетащите «Старт». pointerdown pointerdown
mousedown touchstart
Нажмите вверх или перетащите конец pointerup pointerup
mouseup touchend
click mousedown
mouseup
click
Прокрутка Н/Д
События DOM для каждого типа взаимодействия.

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

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

Клавиатура

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

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

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

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

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

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

Кран

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

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

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

Первой мыслью было бы использовать события pointerdown и pointerup и предположить, что они охватывают все интересующие нас длительности. К сожалению, это не так, как показывает этот крайний случай . Попробуйте открыть этот сайт на мобильном телефоне или с помощью мобильной эмуляции и нажать там, где написано «Нажмите на меня». Этот сайт вызывает задержку нажатия браузера . Видно, что pointerdown , pointerup и touchend отправляются быстро, тогда как mousedown , mouseup и click ждут задержки перед отправкой. Это означает, что если бы мы смотрели только на pointerdown и pointerup , мы бы пропустили продолжительность синтетических событий, которая велика из-за задержки касания браузера и должна быть включена. Поэтому нам нужно измерить pointerdown , pointerup и click , чтобы охватить все взаимодействие.

Тащить

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

Мы также не рассматриваем возможности перетаскивания, реализованные с помощью API перетаскивания, поскольку они работают только на настольных компьютерах.

Прокрутка

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

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

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

Существует несколько событий, которые отправляются при прокрутке пользователем, например touchstart , touchmove и scroll . За исключением события прокрутки, это во многом зависит от устройства, используемого для прокрутки: события касания отправляются при прокрутке пальцем на мобильных устройствах, а события колеса происходят при прокрутке колесиком мыши. События прокрутки запускаются после завершения начальной прокрутки. И вообще, никакое событие DOM не блокирует прокрутку, если только на сайте не используются непассивные прослушиватели событий . Поэтому мы считаем, что прокрутка вообще не связана с событиями DOM. Мы хотим измерить время от момента, когда пользователь переместился достаточно, чтобы выполнить жест прокрутки, до первого кадра, показывающего, что произошла прокрутка.

Как определить задержку взаимодействия?

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

Для этих типов взаимодействий мы хотели бы, чтобы задержка включала продолжительность всех событий, связанных с ними. Поскольку длительность событий для каждой «нисходящей» и «восходящей» части взаимодействия может перекрываться, простейшим определением задержки взаимодействия, позволяющим добиться этого, является максимальная продолжительность любого события, связанного с ним. Возвращаясь к диаграмме клавиатуры, приведенной ранее, это будет длительность keydown , поскольку она длиннее, чем keyup :

Взаимодействие с клавиатурой, выделена максимальная продолжительность

Продолжительность keydown и keyup также может перекрываться. Это может произойти, например, если кадр, представленный для обоих событий, один и тот же, как на следующей диаграмме:

Взаимодействие с клавиатурой, при котором нажатие и отпускание происходят в одном кадре

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

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

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

Объедините все взаимодействия на странице

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

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

Для выполнения этой агрегации нам необходимо решить два вопроса:

  1. Какие числа мы пытаемся агрегировать?
  2. Как нам агрегировать эти цифры?

Мы рассматриваем и оцениваем несколько вариантов. Мы приветствуем ваши мысли по поводу этого агрегата.

Один из вариантов — определить бюджет задержки взаимодействия, который может зависеть от типа (прокрутка, клавиатура, касание или перетаскивание). Например, если бюджет для касаний составляет 100 мс, а задержка касания — 150 мс, то превышение бюджета для этого взаимодействия составит 50 мс. Затем мы могли бы вычислить максимальную задержку, превышающую бюджет для любого взаимодействия пользователя на странице.

Другой вариант — вычислить среднюю или медианную задержку взаимодействий на протяжении всего существования страницы. Таким образом, если бы у нас были задержки 80 мс, 90 мс и 100 мс, то средняя задержка для страницы составила бы 90 мс. Мы также могли бы рассматривать среднее или медианное значение «превышения бюджета», чтобы учитывать разные ожидания в зависимости от типа взаимодействия.

Как это выглядит в API веб-производительности?

Чего не хватает в расписании событий?

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

Еще одним недостатком Event Timing API является отсутствие способа измерения взаимодействия с прокруткой, поэтому мы работаем над включением этих измерений (через Event Timing или отдельный API).

Что вы можете попробовать прямо сейчас?

Прямо сейчас все еще можно вычислить максимальную задержку для касаний/перетаскиваний и взаимодействия с клавиатурой. Следующий фрагмент кода создаст эти две метрики.

let maxTapOrDragDuration = 0;
let maxKeyboardDuration = 0;
const observer = new PerformanceObserver(list => {
  list.getEntries().forEach(entry => {
    switch(entry.name) {
      case "keydown":
      case "keyup":
        maxKeyboardDuration = Math.max(maxKeyboardDuration,
            entry.duration);
        break;
      case "pointerdown":
      case "pointerup":
      case "click":
        maxTapOrDragDuration = Math.max(maxTapOrDragDuration,
            entry.duration);
        break;
    }
  });
});
observer.observe({type: "event", durationThreshold: 16, buffered: true});
// We can report maxTapDragDuration and maxKeyboardDuration when sending
// metrics to analytics.

Обратная связь

Дайте нам знать, что вы думаете об этих идеях, написав по электронной почте: web-vitals-feedback@googlegroups.com!