Улучшение производительности Vue.js приложений

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

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

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

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

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

Функциональные компоненты

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

<template>
  <span v-if="type === 'a'">Type "a"</span>
  <span v-else-if="type === 'b'">Type "b"</span>
  <span v-else-if="type === 'c'">Type "c"</span>
</template>

<script>
export default
  props: {
    type: {
      type: String,
      default: ''
    }
  }
}
</script>

Для того чтобы сделать этот компонент функциональным нам просто нужно добавить атрибут functional.

<template functional>
  <span v-if="props.type === 'a'">Type "a"</span>
  <span v-else-if="props.type === 'b'">Type "b"</span>
  <span v-else-if="props.type === 'c'">Type "c"</span>
</template>

<script>
export default {
  props: {
    type: {
      type: String
    }
  }
}
</script>

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

Когда стоит использовать v-if а когда v-show

<template>
  <div>
    <component-foo v-if="showFoo" />
    <component-bar v-show="showBar" />
  </div>
</template>

Иногда вместо v-if выгоднее использовать v-show. Поясню. Когда мы используем v-if то каждый раз при переключении состояния он создает и уничтожает компонент, то есть вызывает хук destroyed и удаляет все ноды из dom дерева.

Если этот компонент «тяжелый» то каждый раз при переключении состояния, интерфейс будет немного подвисать. Это также зависит от устройств на котором это будет происходить. В v-show при переключении будет просто устанавливать значение стиля display в none и элемент буде всегда существовать на странице.

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

Использование keep-alive

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

<template>
  <div id="app">
    <keep-alive>
      <router-view />
    </keep-alive>
  </div>
</template>

Он выполняет очень простую функцию, говорит Vue кешировать а не удалять компоненты. keep-alive подходит для случаев:

  • Когда требуется кэширование пользовательского ввода в формах.

  • Когда компоненты делают много вызовов API, а вы хотите сделать их только один раз.

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

Также у keep-alive есть дополнительные свойства с помощью которых можно указать что кешировать а что нет.

На мой взгляд keep-alive может хорошо подойти при использовании конструкции “component is” таким образом можно кешировать только определенные компоненты на странице к примеру модальные окна.

<keep-alive>
  <component :is="component" />
</keep-alive>

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

Ленивая загрузка страниц и компонентов

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

[
  {
    path: '/auth',
    name: 'auth',
    component: () => import('./routes/auth')
  },
  {
    path: '/main',
    name: 'main',
    component: MainPage
  }
]

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

Ленивая загрузка также применима и к компонентам.

<template>
  <component-foo />
</template>

<script>
import ComponentFoo from './component-foo'

export default {
  components: {
    ComponentFoo: () => import('./component-foo')
  }
}
</script>

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

Использование v-once

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

<template>
  <div>
    <img v-once src="./logo.png" />
    <span>Hello world<span/>
  </div>
</template>

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

Локальный кеш гетеров

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

<template>
  <span>{{ result }}<span/>
</template>

<script>
export default {
  computed: {
    getCount() {
      return 47
    },
    result() {
      let result = 0

      for(let i = 0; i < 100; i++) {
        result += this.getCount + i
      }
			
      return result
    }
  }
}
</script>

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

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

<template>
  <span>{{ result }}<span/>
</template>

<script>
export default {
  computed: {
    getCount() {
      return 47
    },
    result() {
      const count = this.getCount
      let result = 0

      for(let i = 0; i < 100; i++) {
        result += count + i
      }
			
      return result
    }
  }
}
</script>

Ограничение реактивности с помощью Object.freeze

Есть еще один из вариантов как увеличить скорость работы это не использовать реактивность там где она не нужна. Иногда vuex содержит много редко меняющихся данных, к примеру ответы от АПИ. По умолчанию vuex делает каждое свойство объекта реактивным. В большинстве случаев это приводит к большому потреблению памяти. Используя Object.freeze мы «замораживаем» объект что позволяет не использовать реактивность для него.

setData(state, data) {
  state.data = Object.freeze(data)
}

Данный способ актуален для Vue 2, для Vue 3 способ менее эффективен из-за того что Vue 3 имеет немного другую систему реактивности.
Подробнее про использование Object.freeze можно почитать тут.

Надеюсь эта статья была для Вас полезна. Спасибо!

Источник: https://habr.com/ru/post/719378/


Интересные статьи

Интересные статьи

В этой статье описывается, как команда Netflix TVUI реализовала надежную стратегию для быстрого и легкого обнаружения аномалий производительности до релиза.
В современном мире множество приложений используют трехуровневую архитектуру с базой данных в слоях данных. Наличие юнит-тестов обычно упрощает поддержку продукта, но присутствие базы данных в архит...
Прежде чем начать, хочу уведомить что у меня нет желания как то оскорбить или продвинуть свою точку зрения как истинную. Все системы, приложения, модули и функционал, так или иначе были сделаны по как...
Привет, Хабр! Продолжая проработку темы микросервисов, мы решили предложить вам перевод статьи о тестировании MOA (микросервисно-ориентированных приложений). В последнее время мы уже о...
Angular — это быстрый фреймворк. Он даёт разработчикам обширные возможности по улучшению производительности за счёт тонких настроек. Правда, программистам практически никогда не требуется делать ...