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

Если вы когда-либо использовали Google Pagespeed Insights или Google Lighthouse, значит, вы видели эту оценку эффективности веб-страницы:

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

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

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

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

1. Обновляйте только то, что необходимо

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

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

Но простой код JavaScript, такой как {{ 'value' }} или {{ new Date() }}, не отслеживается Vue как реактивное свойство.

Итак, какое отношение реактивность имеет к дублированию рендеринга?

Допустим, у вас есть массив таких объектов в вашем data объекте:

values: [{id: 1, t: 'a'}, {id: 2, t: 'b'}]

И вы визуализируете его с помощью v-for:

<div v-for="value in values" :key="value.id">{{ value.t }}</div>

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

<div v-for="value in values" :key="value.id">
  {{ value.t }}
  {{ new Date() }}
</div>

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

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

Итак, что делает key и почему мы его передаем? Свойство key помогает Vue понять, что за элемент есть. Если порядок в массиве меняется, key помогает Vue перетасовать элементы на свои места, а не повторять их один за другим.

Указание key важно, но этого недостаточно. Чтобы обеспечить максимальную производительность, вам необходимо создать Child компонентов. Правильно - решение довольно простое. Вам просто нужно разделить свое приложение Vue на небольшие легкие компоненты.

<item :itemValue="value" v-for="item in items" :key="item.id"></item>

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

Прирост производительности от использования компонентов для отображения списков огромен. Если элемент добавлен или удален из массива, Vue больше не будет отображать все компоненты один за другим. Если массив отсортирован, Vue просто перемешивает элементы, полагаясь на предоставленный key.

Если компонент действительно легкий, вы можете сделать его лучше. Вместо передачи полного объекта, такого как value, вы можете передать примитивное свойство (String или Number), например :itemText="value.t”. После этого <item> будет повторно отображаться только в том случае, если переданные вами примитивные значения изменились. Это означает, что даже реактивные изменения приведут к обновлению, но в этом нет необходимости!

2. Устранение дублирования рендеринга

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

Допустим, у вас есть компонент, у которого есть свойство entities в объекте данных.

Если вы выполнили предыдущий шаг, то, вероятно, у вас есть дочерний компонент для рендеринга каждой сущности.

<entity :entity="entity" v-for="entity in entities" :key="entity.id" />

Шаблон сущности выглядит примерно так:

Он выводит entity.value, но также использует user из состояния vuex. Теперь предположим, что у вас есть auth функция, которая обновляет токен пользователя, или глобальное свойство пользователя каким-либо образом изменено. Это приведет к тому, что все представление будет обновляться каждый раз, когда что-то изменится, даже если user.status останется прежним!

Есть несколько способов справиться с этим. Самый простой способ - передать значение user.status как свойство userStatus от родителя. Если значение не изменилось, Vue не будет отображать его снова, поскольку в этом нет необходимости.

Главное здесь - знать о зависимостях рендеринга. Любое изменение свойства, значения данных или вычисленного значения может вызвать повторный рендеринг.

Как определить повторяющиеся рендеры?

Прежде всего загрузите официальные инструменты разработчика Vue.js!

Затем используйте вкладку «Производительность», чтобы измерить производительность вашего приложения Vue. Нажмите start и stop, чтобы запустить проверку производительности, в идеале во время загрузки приложения.

Затем перейдите на вкладку «Рендеринг компонентов». Если ваша страница отображает 100 компонентов, вы должны увидеть 100 created событий.

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

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

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

3. Оптимизация обработки событий

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

Два отличных примера - это события @mouseover и window.scroll. Эти два типа событий могут запускаться много раз даже при нормальном использовании. Если имеющиеся у вас обработчики событий производят дорогостоящие вычисления, эти вычисления будут выполняться несколько раз в секунду, вызывая задержку в вашем приложении. Решение состоит в том, чтобы использовать функцию противодействия, чтобы ограничить количество раз, когда вы обрабатываете эти события.

4. Удалите или уменьшите количество медленных компонентов.

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

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

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

5. Выполнить однократный рендеринг

Это из официальной документации Vue.js. Если у вас есть элементы, которые после того, как все смонтированы, должны отображаться только один раз, вы можете использовать директиву v-once.

Допустим, у вас есть раздел в приложении, для которого требуется, чтобы данные не менялись в течение всего сеанса. Используя директиву v-once, вы гарантируете, что этот раздел будет отображаться только один раз.

6. Виртуальная прокрутка

Это последний шаг к оптимизации производительности вашего приложения Vue. Вы когда-нибудь прокручивали Facebook на рабочем столе? (Или Twitter, или Instagram, или любое популярное приложение для социальных сетей?) Готов поспорить, что да! Прокручивать можно бесконечно, без замедления страницы. Но если у вас есть огромный список для рендеринга в приложении Vue, вы увидите, что чем длиннее она становится, тем медленнее становится страница.

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

Я использовал и то, и другое, и по моему опыту vue-virtual-scroll-list лучше, потому что он проще в использовании и не полагается на абсолютные позиции, которые могут нарушить пользовательский интерфейс.

Заключение

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

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

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