Как стать автором
Обновить

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

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров9.1K

В современном мире 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 можно почитать тут.

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

Теги:
Хабы:
Всего голосов 11: ↑8 и ↓3+6
Комментарии7

Публикации

Истории

Работа

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань