Да, вкладка производительности Chrome ошеломляет

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

В этой статье,

  1. Я вкратце расскажу вам обо всех функциях вкладки «Производительность» Chrome, при этом будет решено большинство обычных любопытных моментов.
  2. Используя то, что мы узнали, мы найдем, что делает наши компоненты React такими медленными, и подумаем, как их улучшить.

Очень простой пример с React

Я написал несколько коротких компонентов <Item /> и <LongList />, чтобы сделать пример для нашей статьи.

И он показывает мне это, который содержит 4500 строк по <Item /> и кнопку, чтобы снова создать все 4500 строк:

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

Это означает, что на ПК более низкого уровня вполне вероятно, что он тоже будет медленным. Давайте на секунду угадаем. Что делает это таким медленным? Сетевые запросы? generateManyRandomThings потому что он производит так много элементов в массиве? Приберегите пока свое предположение. Мы собираемся изучить это тщательно, когда мы подходим к концу этого руководства.

Вы можете увидеть весь исходный код на Github (включая профили производительности Chrome) и получить доступ к развернутому веб-сайту на netlify. Не стесняйтесь открыть инструменты разработки производительности в Chrome и попробовать самостоятельно (однако производственное развертывание может вести себя иначе)

Обзор всех основных функций на одном слайде

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

Разбивая подавляющие части

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

Кнопка перезагрузки

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

Отключить образцы javascript

Отключено (отмечено):

Включено (не отмечено):

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

Включить расширенные инструменты рисования

После установки этого флажка снова запишите производительность.

  1. Нажмите на рамку из раздела Фреймы;
  2. Нажмите внизу панель Слои. Вы увидите слои во время этого кадра и сможете их изучить.

  1. Нажмите на любое из событий рисования в разделе Главное.
  2. Нажмите на профилировщик рисования внизу. Изучите инструкции и время, затраченное на покраску.

Лента новостей

На панели Сводка в нижней части вкладки Производительность будут отображаться цвета, которые напрямую соответствуют средней области ЦП. Один и тот же цвет означает одно и то же на панели Временная шкала и Сводка.

Если вы посмотрите на правую часть временной шкалы, вы увидите FPS (вверху), ЦП (посередине) и NET ( самый нижний).

Маленькая красная полоса на розовой полосе означает, что FPS упал настолько сильно, что, возможно, повредил UX.

Из рисунка выше видно, что график FPS (зеленая часть) показывает резкое снижение в розовой и красной областях.

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

Сроки

React записывает время, затраченное на монтирование и обновление в Chrome, с помощью User Timing API.

Вы можете видеть mount и update тайминги для всех компонентов. Если вы нажмете на диаграмму, нижняя панель на вкладке «Производительность» покажет вам подробную информацию об этом компоненте и его соседних компонентах. Об этом мы поговорим позже.

Если вы хотите проверить, как и какие функции используются в определенных компонентах, нам придется откопать главную панель. Подожди секунду до тех пор.

Chrome также записывает важные события:

Опыт

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

Я попробовал это на medium.com и, к счастью, получил одну смену макета:

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

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

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

Главный

Итак, это интерактивное представление стеков вызовов. Функции вверху - это те, которые были вызваны ранее; те, что внизу, позвонили позже. Вы можете щелкнуть мышью и просмотреть любую из вкладок Сводка, Снизу вверх, Дерево вызовов и Журнал событий. Снизу. Это самые важные части, которые я хотел знать:

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

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

Растр и композитор

Растеризация - это преобразование визуальной информации в пиксели на экране. Использует несколько потоков (которые не являются частью основного потока).

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

Мы рассмотрим эти два вопроса в отдельной статье, потому что они сами по себе составляют такую ​​длинную тему. А пока давайте просто осознаем, что есть эти две вещи.

Сводка, снизу вверх, дерево вызовов и журнал событий

Резюме

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

Легенда справа показывает:

  • Загрузка: время, затраченное на загрузку ресурсов
  • Сценарии: время, затраченное на синтаксический анализ и оценку javascript
  • Рендеринг (макет): время, затрачиваемое на вычисление стилей и позиций элементов на странице. Не знаю, почему Chrome называет это Макет на главной панели и Визуализация здесь.
  • Рисование: время, затрачиваемое на заливку пикселей
  • Система: эффективно, также может называться другими. Все действия, не относящиеся к категориям Loading, Scripting, Rendering, Painting и GPU.

Вверх дном

  • Самостоятельное время: время, затрачиваемое на выполнение кода в самой функции, за исключением времени на выполнение других функций, которые она вызывает. (в примере useState и moutState имеют почти 0% собственного времени, потому что длинные линии диаграммы внезапно заканчиваются на generateManyRandomStrings, что вызывает все тяжелые работы.
  • Общее время: время, затрачиваемое на выполнение функций (до конца) из текущей функции.
  • Ищите ответвления с высоким общим временем, а затем найдите блоки с высоким собственным временем. Это может быть причиной некоторых проблем с производительностью.
  • В приведенном выше примере на generateManyRandomThings в совокупности приходится 1,3% времени рендеринга из LongList. Но его общее время составляет 22,5%. Таким образом, должно быть, что выполняемые функции выполняют дорогостоящую работу (фактическая работа, выполняемая исключительно внутри этой функции, не очень медленная).

  • Не путайте: если вы последовательно открываете выпадающие списки под первой вкладкой, вы возвращаетесь к исходной функции, которая была вызвана. Вы опускаетесь в стеке вызовов. Вы НЕ поднимаетесь.

Дерево вызовов

  • Он отслеживает корневую активность (или действия), которая вызвала вызов функции.
  • В приведенном выше примере корневым действием initBackend является Function Call.

Журнал событий

  • Он показывает хронологический порядок событий.
  • В приведенном выше примере LongList сначала был вызван при 256,7 мс, затем useState при 290,0 мс, а затем generateManyRandomThings при 290,2 мс.

Итак, как мне использовать это с React?

Хороший вопрос! Вернемся к нашему коду. Затем давайте снова замедлим работу нашего процессора. Я установил замедление в 4 раза. Теперь давайте попробуем почувствовать первую скорость загрузки (нажмите кнопку Начать профилирование и перезагрузить страницу). К вашему сведению, вы можете скачать профили производительности, которые я использую в этом примере, с github.

Ну, конечно, прошло какое-то время, прежде чем вы впервые увидели что-нибудь в браузере. А теперь посмотрим на запись:

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

Из вышесказанного видно, что браузер потратил первые 500 мс на уничтожение предыдущей веб-страницы (которая фактически была той же localhost:3000), запросы по сети, синтаксический анализ и компиляцию таких ресурсов, как файлы javascript и html.

Сразу после 500 мс мы видим, что вызываются фактические функции из самой библиотеки React, а также нашего ./src/index.js. Давайте посмотрим на это на вкладке Тайминги:

Красный прямоугольник - это выполнение LongList (компоненты тоже являются функциями!), А синий прямоугольник - выполнение многих Item.

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

Но после проверки журнала мы обнаруживаем, что виновником является не generateManyRandomThings (под LongList):

1. Даже просто взглянув на диаграмму, становится очевидно, что generateManyRandomThings - это лишь небольшая часть всего процесса рендеринга <LongList />. generateManyRandomThings был вызван дважды, потому что useState неоднократно дважды вызывался во время рендеринга; но оба были еще невысокими. Ниже указана продолжительность первого выполнения generateManyRandomThings. Как видите, на самом деле это всего лишь небольшая часть (красный кружок) под render:

2. render заняло почти 2 секунды, а generateManyRandomThings заняло всего 54,1 мс (2,7% от общего времени render):

Тогда в чем основная причина медлительности? Что ж, оказывается, виноват <Item />, как вы уже могли легко заметить.

Так много повторяющихся процессов происходит для каждого из 4500 различных <Item />. Как тогда мы можем это оптимизировать? На самом деле, мы, возможно, собираемся использовать что-то вроде виртуального списка, чтобы вы отображали только то, что находится внутри вашего текущего окна просмотра. Это сильно сократится. Поскольку создание виртуального списка не является здесь основной темой, давайте просто представим, что мы сделали это, уменьшив количество элементов до 100, и посмотрим, как снова работает наше приложение React. Ради доказательства производительности, давайте все же сделаем 4500 элементов в массиве и отрендерим только 100 <Item /> s, например:

И результат…? Даже не вдаваясь в подробности, мы уже можем почувствовать, что время начальной загрузки (момент изменения строк) значительно сократилось.

ах, теперь мы видим, что собственное время LongList, наконец, стало чем-то похожим на общее время выполнения всех Item с:

Хотя может показаться очень простым, что установка 4500 компонентов происходит медленнее, чем размещение строк и чисел в массиве, всегда стоит опробовать аудит производительности с помощью вкладки «Производительность Chrome», потому что, пока вы не проверите реальную производительность с помощью журналов и статистики, вы, по сути, просто предполагаете какая часть должна быть самой медленной. В сложных приложениях React вероятность того, что так будет хорошо работать, очень мала.

Последнее любопытство

Но почему useState все равно вызывается дважды в одном монтировании, вот так ?:

Ну, это не было связано с тем, что мы сделали! Дэн Абрамов говорит, что это всегда происходит, когда вы используете <React.StrictMode>. Так что в этом нет ничего плохого. Если мы изменим

to

Он покажет вам только одно выполнение useState, например:

Заключительные примечания

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

Спасибо за чтение!

Первоначально опубликовано на странице https://9oelm.github.io/2020-08-03--Learn-all-major%20functionalities-on-Chromes-Performance-tab-and-practice-it-with-a- простой-React-проект / .