Измеряем производительность веб-приложений
Здравствуйте!
Сегодня — перевод чертовски интересной и полезной статьи «Performance metrics. What’s this all about?».
Измерение производительности загрузки страницы — сложная задача, поэтому разработчики Chrome вместе с сообществом работают над прогрессивными веб-метриками (PWM). Что такое PWM и зачем они нам?
Сперва немного истории.
Некоторое время назад у нас было два основных события для измерения производительности. DOMContentLoaded вызывалось, когда страница была загружена, но скрипты только начали выполняться. load событие вызывалось, когда страница была полностью загружена и отработали все скрипты, так что пользователь мог полноценно взаимодействовать со страницей.
Если мы взглянем, к примеру, на таймлайн загрузки reddit.com (Chrome Dev Tools помогают нам, отмечая интересующие точки синими и красными вертикальными линиями), мы сможем понять, почему эти метрики не особо помогают.
Вернемся в настоящее. Теперь window.onload не отражает пользовательского восприятия так, как было раньше. Об этом пишет Стив Саудерс в статье «Moving beyond window.onload()»
Естественно. Проблема DOMContentLoaded в том, что время парсинга и выполнения скриптов может быть слишком большим, если скрипты очень велики, например, на мобильных устройствах. Скажем, таймлайн, который был измерен с имитацией работы через сеть 3G, показывает время примерно в 10 секунд до полной загрузки.
Иными словами, загрузка идет слишком долго, чтобы как-то анализировать проблемы производительности. Так что, можем ли мы опираться на эти метрики? Какую информацию мы можем из них извлечь? И главный вопрос — как пользователи ощущают загрузку страницы от начала до полностью загруженной страницы?
Почему ощущения пользователей так важны? Мы обратимся к материалу «Leveraging the Performance Metrics that Most Affect User Experience» от разработчиков Chrome, который еще раз подчеркивает проблему загрузки.
Взглянув на гистограмму, где по оси Х показывается время загрузки, а по оси Y относительное количество пользователей с соответственным временем загрузки, мы сможем понять, что не все пользователи получают страницу меньше, чем за две секунды.
Общее время загрузки, которое в нашем эксперименте составляет около 17 секунд, не дает нам никаких полезных сведений о том, как пользователи ощущают время загрузки. Что они видят в течении этих секунд? Пустой экран? Частично загруженную страницу? Может, контент загружен, но заморожен, то есть пользователи не могут скроллить или вводить данные в форму? Ответы на эти вопросы помогут:
- Улучшить UX
- Привлечь больше пользователей в приложение
- Увеличить пользу для владельцев продукта — количество пользователей, клиентов, денег
Так что парни попытались прочесть мысли пользователей и предвидеть, что пользователь думает в течении этих 17 секунд:
- Это работает? Началась ли вообще загрузка страницы, ответил ли сервер?
- Есть ли в этом польза? Загрузился ли контент, который я ожидаю в первую очередь?
- Можно ли этим пользоваться? Могу ли я взаимодействовать со страницей или еще нет?
- Это восхитительно? Был ли я приятно удивлен отсутствием ненужной анимации, медленных кастомных шрифтов и всего такого?
Если DOMContentLoaded или load метрики не могут ответить на эти вопросы, кто может?
Progressive Web Metrics
PWM — метрики, помогающие определить проблемы производительности. Несмотря на существование load и DOMContentLoaded, PWM дают разработчикам гораздо больше информации о том, как загружается страница. Давайте пройдемся по PWM, глядя на трейс reddit.com и попробуем понять смысл каждой метрики.
First Paint (FP)
Я несколько слукавил, говоря, что у нас есть только две метрики. Dev Tools дают нам еще одну метрику — FP, время до начала рендеринга. Иными словами, это время, в которое пользователь будет видеть пустую страницу (ниже скриншот пустой страницы msn.com). Вот спецификация: github.com/w3c/paint-timing
Чтобы понять, как это работает, мы взглянем под капот графического слоя Chromium, для примера.
Событие FP вызывается, когда отрендерен один лишь графический слой, без текста, изображений, canvas и всего такого. Однако FP дает некоторую информацию, потенциально полезную разработчикам.
Поскольку это не стандартная метрика, ее измерение становится немного сложным. Есть разные техники измерения, например:
- использование requestAnimationFrame
- отслеживание загрузки css
- даже использование DOMContentLoaded и load событий (их проблемы описаны выше)
Но несмотря на все усилия, FP имеет низкую ценность, поскольку текст и изображения могут быть отрисованы несколько позже, в зависимости от веса страницы и размера загружаемых ресурсов и скриптов. Эта метрика не относится к PWM, но она поможет нам понять, как работают остальные метрики.
Для понимания того, как на самом деле отображается контент, потребовалась другая метрика.
First Contentful Paint (FCP)
Это время, за которое пользователь увидит какой-то контент, что-то отличное от просто пустой страницы. Это может быть что угодно — текст, SVG или даже canvas. В результате пользователь понимает, грузится ли вообще страница после того, как он ввел URL и нажал на Enter.
FCP вызывается в момент отрисовки текста (причем текст, ожидающий загрузки шрифта, тут не учитывается), изображения или какого-то иного контента. Время между FP и FCP варьируется от миллисекунд до секунд. Различие четко видно на скриншотах выше. Вот почему метрика, показывающая реальную отрисовку страницы, важна для нас. Посмотрите также спецификацию FCP.
В чем польза метрики FCP для разработчиков? Если время до FCP слишком велико, причин две:
- низкая производительность сети
- объемные ресурсы, требующие много времени на загрузку
Почитайте побольше насчет производительности сети в материале «High Performance Browser Networking» от Ильи Григорика, чтобы устранить влияние этих факторов.
First Meaningful Paint (FMP)
Время, за которое пользователь увидит основной контент на экране — полезно ли оно для нас?
Что такое основной контент?
Это когда показаны:
- заголовок и текст для блога
- поисковая фраза для поисковика
- изображения, если они критичны для интернет-магазина
Но сюда не входят:
- спиннеры или иная анимация загрузки
- FOUC
- панель навигации или заголовок страницы
FMP — рендеринг, следующий за наибольшим изменением структуры страницы. Из-за реализации Chromium, эта метрика снимается посредством LayoutAnalyzer, который собирает все изменения макета, и измеряет время наибольшего изменения. Это время и есть FMP.
В чем польза FMP для разработчиков?
Если основной контент не показывается слишком долго, это значит, что слишком много ресурсов (изображения, стили, шрифты, скрипты) имеют высокий приоритет, и в итоге блокируют FMP.
Я не хочу повторять уже известные практики по предотвращению этих проблем, так что просто оставлю эти ссылки здесь:
- Preload, Prefetch And Priorities in Chrome by Addy Osmani
- Critical Request by Ben Schwarz
- The State of the Web by Karolina Szczur
- Practical Performance (Polymer Summit 2016) from Paul Irish and Sam Saccone
Visually Ready
Когда страница выглядит готовой, но браузер еще не закончил выполнять все скрипты.
Estimated Input Latency
Метрика, призванная определить, насколько адекватно приложение отвечает на действия пользователя. Но прежде чем углубиться, я хочу ввести некоторую терминологию.
Длинные задачи
Под капотом браузера весь пользовательский ввод оборачивается в задачи (UI tasks), которые ставятся в очередь в основном потоке. Кроме этого, браузеру нужно распарсить, скомпилировать и запустить скрипты на странице (application tasks). Если время на каждый application task занимает много времени, пользовательский ввод может быть блокирован, пока задача не закончится. В результате взаимодействие пользователя со страницей затрудняется, а внешне это выглядит как лаги и тормоза.
Проще говоря, длинные задачи — это выполнение скриптов дольше 50 мсек. Спецификация доступна по ссылке: w3c.github.io/longtasks
API долгих задач уже реализовано в Chrome и уже используется для измерения загруженности главного потока.
Возвращаясь к метрике Estimated Input Latency: пользователь ожидает, что страница мгновенно ответит на его действия, но если главный поток перегружен длинными задачами, пользователь будет обеспокоен. Если UX критичен для вашего приложения, вам стоит почитать статью «Measure Performance with the RAIL Model», где описаны возможные оптимизации по этой метрике.
First Interactive
Событие, возникающее, когда приложение готово взаимодействовать с пользователем. Это совокупность трех событий:
- FMP
- DOMContentLoaded
- Страница визуально готова на 85%
Метрика First Interactive разбивается на две метрики Time to First Interactive (TTFI) и Time to First Consistently Interactive (TTCI). Причины разделения таковы:
- Определение минимального порога, когда UI отзывается хорошо, но ничего страшного, если это не так.
- Определение состояния, когда приложение полностью готово взаимодействовать, согласно гайдлайнам RAIL
TTCI
Глядя с конца трассировки, найдем окно, когда нет активной загрузки в течении пяти секунд и все длинные задачи завершены. Время между началом окна и концом последней долгой задачи как раз и будет TTCI.
TTFI
Проанализируем трассировку с начала до конца. После FMP есть небольшое окно в три секунды. Его продолжительности достаточно, чтобы сказать, что страница достаточно отзывчива к пользователю. Несмотря на то, что в этот момент могут быть отдельные длинные задачи, мы игнорируем этот факт.
Отдельные задачи — задачи, запущенные достаточно далеко от FMP, длительностью до 250 мсек, изолированные до и после временем в 1 секунду. Например, это может быть загрузка сторонней рекламы или скриптов аналитики. Иногда отдельные задачи длиннее 250 мсек могут оказывать серьезное влияние на производительность. Яркий пример — скрипты определения блокировщиков рекламы. Посмотрите также спецификацию TTFI/TTCI.
Насколько TTFI и TTCI полезны для разработчиков? Вот пример, когда поток надолго занят между Visually Ready и First Interactive:
Это одна из самых сложных проблем производительности, и нет простого способа ее решить. Решение сильно зависит от конкретного приложения и его реализации. Вот материалы, которые могут вам помочь: developers.google.com/web/tools/chrome-devtools/evaluate-performance.
Visually Complete / Speed Index
Visually Complete вычисляется посредством снятия скриншотов страницы и сравнения их с помощью алгоритма Speed Index. Иногда это бывает совсем не просто: если на странице есть меняющиеся изображения, например карусель, будет сложно получить точный результат метрики Visually Complete.
Speed Index сам по себе вычисляет медиану между результатами Visually Complete. Чем меньше значение, тем лучше. 100% результат Visually Complete — финальная точка, когда перед пользователем встает последний вопрос: нравится ли ему то, что он видит?
Суммируем
Это не все метрики PWM, но я выбрал самые важные. Выше я добавил много ссылок на материалы, которые помогут вам улучшить производительность на всех стадиях. Вдобавок я оставлю ссылки на инструменты, которые могут измерять эти метрики:
P.S.
Лучшие результаты дают Lighthouse или pwmetrics. Calibre и WPT на самом деле используют Lighthouse для получения метрик. Если вы хотите снять метрики собственноручно, API под названием PerformanceObserver может вам помочь. Вот пример из спецификации:
const observer = new PerformanceObserver(list => { list .getEntries() // Get the values we are interested in .map(({ name, entryType, startTime, duration }) => { const obj = { "Duration": duration, "Entry Type": entryType, "Name": name, "Start Time": startTime, }; return JSON.stringify(obj, null, 2); }) // Display them to the console .forEach(console.log); // maybe disconnect after processing the events. observer.disconnect(); }); // retrieve buffered events and subscribe to new events // for Resource-Timing and User-Timing observer.observe({ entryTypes: ["resource", "mark", "measure"], buffered: true });
Спасибо всем за изумительную работу по подготовке спецификаций, статей и инструментов!