Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру 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
можно почитать тут.
Надеюсь эта статья была для Вас полезна. Спасибо!