Эта статья сослалась на основной член Vue.jsGuillaume ChauВ теме, которой поделилась Vue conf в США в 2019 году: раскрыто 9 секретов производительности, были упомянуты девять навыков оптимизации производительности Vue.js.
Я читал его обменPPTПосле этого также прочитайте соответствующиеИсходный код проекта, после глубокого понимания принципа его оптимизации, я также применил некоторые из этих методов оптимизации к своей обычной работе и добился неплохих результатов.
Этот шеринг можно сказать очень практичный, но, похоже, мало кто знает и обращает внимание.Пока у проекта лишь жалкие сотни звезд. Несмотря на то, что прошло два года с момента обмена большим братом, навыки оптимизации в нем не устарели.Чтобы дать большему количеству людей понять и освоить практические навыки, я решил повторно обработать его обмен и уточнить его принцип оптимизации, и сделать определенную степень расширения и расширения.
Эта статья в основном для версии Vue.js 2.x, в конце концов, в следующий раз Vue.js 2.x по-прежнему является основной версией нашей работы.
Предлагаю при изучении этой статьи вытащить исходный код проекта и запустить его локально, чтобы увидеть разницу в эффекте до и после оптимизации.
Functional components
Первый совет, функциональные компоненты, вы можете проверить этоОнлайн-пример.
Код компонента до оптимизации выглядит следующим образом:
<template>
<div class="cell">
<div v-if="value" class="on"></div>
<section v-else class="off"></section>
</div>
</template>
<script>
export default {
props: ['value'],
}
</script>
Код оптимизированного компонента выглядит следующим образом:
<template functional>
<div class="cell">
<div v-if="props.value" class="on"></div>
<section v-else class="off"></section>
</div>
</template>
Затем мы визуализируем 800 компонентов до и после оптимизации в родительском компоненте и запускаем обновление компонентов, изменяя данные в каждом кадре, открываем панель производительности Chrome, чтобы записать их производительность, и получаем следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти два рисунка, мы видим, что выполнение до оптимизацииscript
Это занимает больше времени, чем оптимизированный, и мы знаем, что движок JS является однопоточным операционным механизмом, и поток JS будет блокировать поток пользовательского интерфейса, поэтому, когда время выполнения скрипта слишком велико, он будет блокировать рендеринг и привести к зависанию страницы. и оптимизированныйscript
Время выполнения короткое, поэтому работает лучше.
Итак, почему сокращается время выполнения JS с функциональными компонентами? Это начинается с принципа реализации функциональных компонентов.Вы можете понимать это как функцию, которая может отображать и генерировать часть DOM в соответствии с данными контекста, которые вы передаете.
В отличие от обычных компонентов объектного типа, функциональные компоненты не рассматриваются как реальные компоненты.Мы знаем, что вpatch
В процессе, если вы столкнетесь с узлом, это компонентvnode
, рекурсивно выполнит процесс инициализации подкомпонента, в то время как функциональный компонентrender
сгенерированный является общимvnode
, не будет рекурсивного процесса дочернего компонента, поэтому накладные расходы на рендеринг будут намного ниже.
Таким образом, функциональные компоненты не имеют состояния, у них нет реактивных данных, у них нет ловушек жизненного цикла. Вы можете думать об этом как об удалении части DOM в обычном шаблоне компонента и отображении его с помощью функции, что является своего рода повторным использованием на уровне DOM.
Child component splitting
Второй трюк, разделение подкомпонентов, вы можете проверить этоОнлайн-пример.
Код компонента до оптимизации выглядит следующим образом:
<template>
<div :style="{ opacity: number / 300 }">
<div>{{ heavy() }}</div>
</div>
</template>
<script>
export default {
props: ['number'],
methods: {
heavy () {
const n = 100000
let result = 0
for (let i = 0; i < n; i++) {
result += Math.sqrt(Math.cos(Math.sin(42)))
}
return result
}
}
}
</script>
Код оптимизированного компонента выглядит следующим образом:
<template>
<div :style="{ opacity: number / 300 }">
<ChildComp/>
</div>
</template>
<script>
export default {
components: {
ChildComp: {
methods: {
heavy () {
const n = 100000
let result = 0
for (let i = 0; i < n; i++) {
result += Math.sqrt(Math.cos(Math.sin(42)))
}
return result
},
},
render (h) {
return h('div', this.heavy())
}
}
},
props: ['number']
}
</script>
Затем мы визуализируем 300 компонентов до и после оптимизации в родительском компоненте и запускаем обновление компонентов, изменяя данные в каждом кадре, открываем панель производительности Chrome, чтобы записать их производительность, и получаем следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти два рисунка, мы видим, что оптимизированное выполнениеscript
Время значительно меньше, чем до оптимизации, поэтому производительность лучше.
Так почему же есть разница? Давайте посмотрим на компоненты перед оптимизацией. Пример передаетheavy
Функция имитирует трудоемкую задачу, и эта функция выполняется один раз при каждом рендеринге, поэтому каждый рендеринг компонента будет занимать много времени для выполнения JavaScript.
Оптимизированный способ состоит в том, чтобы поставить эту трудоемкую задачуheavy
Подкомпонент для логики выполнения функцииChildComp
Инкапсулированный, потому что обновление Vue — это гранулярность компонентов, хотя каждый кадр вызывает повторный рендеринг родительского компонента посредством модификации данных, ноChildComp
Но он не будет перерисовываться, потому что внутри него также нет никаких реагирующих изменений данных. Поэтому оптимизированный компонент не будет выполнять трудоемкие задачи в каждом рендеринге, а естественное время выполнения JavaScript будет сокращено.
Тем не менее, я выдвинул несколько разных точек зрения на этот метод оптимизации.issue, я думаю, что в этом сценарии лучше использовать вычисляемые свойства для оптимизации, чем разбивать подкомпоненты. Благодаря функции кэширования самого вычисляемого свойства трудоемкая логика будет выполняться только при первом рендеринге, и нет дополнительных затрат на рендеринг дочерних компонентов с использованием вычисляемых свойств.
В практической работе встречается множество сценариев, в которых использование вычисляемых свойств используется для оптимизации производительности, ведь это также отражает идею оптимизации изменения пространства во времени.
Local variables
Третий трюк, локальные переменные, вы можете проверить этоОнлайн-пример.
Код компонента до оптимизации выглядит следующим образом:
<template>
<div :style="{ opacity: start / 300 }">{{ result }}</div>
</template>
<script>
export default {
props: ['start'],
computed: {
base () {
return 42
},
result () {
let result = this.start
for (let i = 0; i < 1000; i++) {
result += Math.sqrt(Math.cos(Math.sin(this.base))) + this.base * this.base + this.base + this.base * 2 + this.base * 3
}
return result
},
},
}
</script>
Код оптимизированного компонента выглядит следующим образом:
<template>
<div :style="{ opacity: start / 300 }">{{ result }}</div>
</template>
<script>
export default {
props: ['start'],
computed: {
base () {
return 42
},
result ({ base, start }) {
let result = start
for (let i = 0; i < 1000; i++) {
result += Math.sqrt(Math.cos(Math.sin(base))) + base * base + base + base * 2 + base * 3
}
return result
},
},
}
</script>
Затем мы визуализируем 300 компонентов до и после оптимизации в родительском компоненте и запускаем обновление компонентов, изменяя данные в каждом кадре, открываем панель производительности Chrome, чтобы записать их производительность, и получаем следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти два рисунка, мы видим, что оптимизированное выполнениеscript
Время значительно меньше, чем до оптимизации, поэтому производительность лучше.
Здесь в основном представлены рассчитанные свойства компонентов до и после оптимизации.result
различия в реализации, к компонентам до оптимизации обращаются несколько раз в процессе расчетаthis.base
, тогда как оптимизированный компонент будет использовать локальные переменные перед вычислениемbase
, кешthis.base
, затем прямой доступbase
.
Итак, почему эта разница вызывает разницу в производительности, причина в том, что каждый раз, когда вы посещаетеthis.base
когда, потому чтоthis.base
является реактивным объектом, поэтому вызовет егоgetter
, а затем выполните логический код, связанный со сбором зависимостей. Подобная логика выполняется больше, как в примере, сотни циклов обновляют сотни компонентов, каждый компонент срабатываетcomputed
При пересчете и многократном выполнении логики, связанной со сбором зависимостей, производительность, естественно, упадет.
С точки зрения спроса,this.base
Достаточно один раз выполнить сбор зависимостей, поместить егоgetter
Результат оценки возвращается в локальную переменнуюbase
, зайдите позжеbase
не сработает, когдаgetter
, и не будет следовать логике сбора зависимостей, а производительность, естественно, улучшится.
Это очень полезный трюк оптимизации производительности. Потому что, когда многие люди разрабатывают проекты Vue.js, они обычно пишут напрямую всякий раз, когда берут переменные.this.xxx
, потому что большинство людей не замечают посещенияthis.xxx
вещи за кадром. Когда количество посещений невелико, проблема с производительностью не становится заметной, но как только количество посещений увеличивается, например, несколько посещений в большом цикле, например, возникают проблемы с производительностью.
Когда я оптимизировал производительность компонента таблицы ZoomUI ранее, вrender table body
Я использовал метод оптимизации локальных переменных и написал тест для сравнения производительности: при рендеринге таблицы 1000 * 10 производительность повторного рендеринга обновленных данных таблицы ZoomUI почти вдвое выше, чем у таблицы ElementUI.
Reuse DOM with v-show
Четвертый трюк, используйтеv-show
Чтобы повторно использовать DOM, вы можете проверить этоОнлайн-пример.
Код компонента до оптимизации выглядит следующим образом:
<template functional>
<div class="cell">
<div v-if="props.value" class="on">
<Heavy :n="10000"/>
</div>
<section v-else class="off">
<Heavy :n="10000"/>
</section>
</div>
</template>
Код оптимизированного компонента выглядит следующим образом:
<template functional>
<div class="cell">
<div v-show="props.value" class="on">
<Heavy :n="10000"/>
</div>
<section v-show="!props.value" class="off">
<Heavy :n="10000"/>
</section>
</div>
</template>
Затем мы визуализируем 200 компонентов до и после оптимизации в родительском компоненте и запускаем обновление компонентов, изменяя данные в каждом кадре, и открываем панель производительности Chrome, чтобы записать их производительность, и получаем следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти два рисунка, мы видим, что оптимизированное выполнениеscript
Время значительно меньше, чем до оптимизации, поэтому производительность лучше.
Основное различие между оптимизацией до и после заключается в использованииv-show
команда замененаv-if
Инструкции по замене явных и неявных компонентов, хотя с точки зрения производительностиv-show
а такжеv-if
Точно так же оба управляют отображением и сокрытием компонентов, но внутренний разрыв в реализации все еще очень велик.
v-if
Инструкция будет скомпилирована в тернарный оператор на этапе компиляции, а условный рендеринг, такой как шаблон компонента перед оптимизацией, после компиляции сгенерирует следующую функцию рендеринга:
function render() {
with(this) {
return _c('div', {
staticClass: "cell"
}, [(props.value) ? _c('div', {
staticClass: "on"
}, [_c('Heavy', {
attrs: {
"n": 10000
}
})], 1) : _c('section', {
staticClass: "off"
}, [_c('Heavy', {
attrs: {
"n": 10000
}
})], 1)])
}
}
когда условиеprops.value
Когда значение , вызовет обновление соответствующего компонента, дляv-if
Визуализированные узлы из-за старых и новых узловvnode
Непоследовательно, в процессе сравнения основных алгоритмов сравнения старые будут удалены.vnode
узел, создать новыйvnode
узел, затем новыйHeavy
компоненты, будут испытыватьHeavy
Сам компонент инициализируется и рендеритсяvnode
,patch
и так далее.
Так что используйтеv-if
Каждый раз, когда компонент обновляется, создается новыйHeavy
Подкомпоненты, когда есть много обновленных компонентов, естественно, будут снижать производительность.
и когда мы используемv-show
инструкции оптимизированный шаблон компонента компилируется для создания следующей функции рендеринга:
function render() {
with(this) {
return _c('div', {
staticClass: "cell"
}, [_c('div', {
directives: [{
name: "show",
rawName: "v-show",
value: (props.value),
expression: "props.value"
}],
staticClass: "on"
}, [_c('Heavy', {
attrs: {
"n": 10000
}
})], 1), _c('section', {
directives: [{
name: "show",
rawName: "v-show",
value: (!props.value),
expression: "!props.value"
}],
staticClass: "off"
}, [_c('Heavy', {
attrs: {
"n": 10000
}
})], 1)])
}
}
когда условиеprops.value
Когда значение , вызовет обновление соответствующего компонента, дляv-show
Отрисованные узлы из-за старых и новыхvnode
последовательны, им просто нужно сохранитьpatchVnode
Вот и все, так как он заставляет узлы DOM показывать и скрывать?
это былоpatchVnode
В процессе внутреннийv-show
Функция хука, соответствующая инструкцииupdate
, то он будет основан наv-show
Значение, связанное с директивой для установки значения элемента DOM, на который она действует.style.display
Значение контролирует отображение и скрытие.
Поэтому по сравнению сv-if
продолжайте удалять и создавать новый DOM с функциями,v-show
просто обновляет явные и неявные значения существующей модели DOM, поэтомуv-show
стоит больше, чемv-if
Меньше, чем сложнее внутренняя структура DOM, тем больше разница в производительности.
ноv-show
в сравнении сv-if
Преимущество в производительности на этапе обновления компонента, если только на этапе инициализации,v-if
производительность выше, чемv-show
, причина в том, что он отображает только одну ветвь, аv-show
Обе ветки отображаются черезstyle.display
Для управления отображением и скрытием соответствующего DOM.
В использованииv-show
, будут отображены все компоненты внутри ветки, будут выполнены соответствующие функции ловушки жизненного цикла, а использованиеv-if
, компоненты внутри ветки, которые не были затронуты, не будут отображаться, и соответствующие функции обработчика жизненного цикла не будут выполняться.
Поэтому нужно понимать их принципы и отличия, чтобы можно было использовать подходящие команды в разных сценариях.
KeepAlive
Совет пятый, используйтеKeepAlive
Компонент кэширует DOM, вы можете проверить этоОнлайн-пример.
Код компонента до оптимизации выглядит следующим образом:
<template>
<div id="app">
<router-view/>
</div>
</template>
Код оптимизированного компонента выглядит следующим образом:
<template>
<div id="app">
<keep-alive>
<router-view/>
</keep-alive>
</div>
</template>
Мы нажимаем кнопку, чтобы переключаться между простой страницей и тяжелой страницей, которые будут отображать разные представления, а рендеринг тяжелой страницы требует очень много времени. Мы открываем панель производительности Chrome, чтобы записать их производительность, а затем выполняем вышеуказанные операции до и после оптимизации, и мы получим следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти два рисунка, мы видим, что оптимизированное выполнениеscript
Время значительно меньше, чем до оптимизации, поэтому производительность лучше.
В неоптимизированном сценарии каждый раз, когда мы нажимаем кнопку для переключения вида маршрутизации, компонент будет повторно визуализироваться, а визуализированный компонент будет инициализирован компонентом.render
,patch
Ожидание процесса, если компоненты более сложные или глубоко вложенные, весь рендеринг займет много времени.
при использованииKeepAlive
после того, какKeepAlive
После того, как обернутый компонент визуализируется в первый раз,vnode
И DOM будет кешироваться, и тогда при следующем повторном рендеринге компонента он получит соответствующие данные прямо из кешаvnode
и DOM, а затем рендерить, нет необходимости снова проходить инициализацию компонента,render
а такжеpatch
Подождите, пока ряд процессов уменьшитсяscript
время выполнения и лучшая производительность.
но использоватьKeepAlive
Компонент стоит недешево, потому что он будет занимать больше памяти для кэширования, что является типичным применением оптимизации пространства-времени.
Deferred features
Совет шестой, используйтеDeferred
Компонент задерживает рендеринг компонентов в пакетах, вы можете проверить этоОнлайн-пример.
Код компонента до оптимизации выглядит следующим образом:
<template>
<div class="deferred-off">
<VueIcon icon="fitness_center" class="gigantic"/>
<h2>I'm an heavy page</h2>
<Heavy v-for="n in 8" :key="n"/>
<Heavy class="super-heavy" :n="9999999"/>
</div>
</template>
Код оптимизированного компонента выглядит следующим образом:
<template>
<div class="deferred-on">
<VueIcon icon="fitness_center" class="gigantic"/>
<h2>I'm an heavy page</h2>
<template v-if="defer(2)">
<Heavy v-for="n in 8" :key="n"/>
</template>
<Heavy v-if="defer(3)" class="super-heavy" :n="9999999"/>
</div>
</template>
<script>
import Defer from '@/mixins/Defer'
export default {
mixins: [
Defer(),
],
}
</script>
Мы нажимаем кнопку, чтобы переключаться между простой страницей и тяжелой страницей, которые будут отображать разные представления, а рендеринг тяжелой страницы требует очень много времени. Мы открываем панель производительности Chrome, чтобы записать их производительность, а затем выполняем вышеуказанные операции до и после оптимизации, и мы получим следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти две картинки, мы можем обнаружить, что когда мы переключались с простой страницы на тяжелую страницу перед оптимизацией, когда рендеринг близился к концу, страница все еще отображалась как простая страница, из-за чего у людей возникало ощущение, что страница застряла. После оптимизации, когда мы переключаемся с простой страницы на тяжелую страницу, тяжелая страница уже отображается в передней позиции рендеринга, а тяжелая страница визуализируется постепенно.
Разница между оптимизацией до и после в основном заключается в том, что последняя используетDefer
этоmixin
, то как конкретно это работает, давайте разбираться:
export default function (count = 10) {
return {
data () {
return {
displayPriority: 0
}
},
mounted () {
this.runDisplayPriority()
},
methods: {
runDisplayPriority () {
const step = () => {
requestAnimationFrame(() => {
this.displayPriority++
if (this.displayPriority < count) {
step()
}
})
}
step()
},
defer (priority) {
return this.displayPriority >= priority
}
}
}
}
Defer
Основная идея состоит в том, чтобы разделить один рендеринг компонента на несколько раз, который поддерживается внутри.displayPriority
переменная, а затем передатьrequestAnimationFrame
Увеличивайте рендеринг каждого кадра доcount
. затем используйтеDefer mixin
внутри компонента может проходитьv-if="defer(xxx)"
Способ управленияdisplayPriority
увеличить доxxx
при рендеринге некоторых блоков.
Если у вас есть компоненты, для рендеринга которых требуется время, используйтеDeferred
Рекомендуется выполнять прогрессивный рендеринг, чтобы избежать однократногоrender
Рендеринг завис из-за того, что время выполнения JS слишком велико.
Time slicing
Седьмой совет, используйтеTime slicing
Техника резки временных отрезков, вы можете проверить этоОнлайн-пример.
Код до оптимизации выглядит следующим образом:
fetchItems ({ commit }, { items }) {
commit('clearItems')
commit('addItems', items)
}
Оптимизированный код выглядит следующим образом:
fetchItems ({ commit }, { items, splitCount }) {
commit('clearItems')
const queue = new JobQueue()
splitArray(items, splitCount).forEach(
chunk => queue.addJob(done => {
// 分时间片提交数据
requestAnimationFrame(() => {
commit('addItems', chunk)
done()
})
})
)
await queue.start()
}
Сначала мы нажимаемGenterate items
кнопку, чтобы создать 10 000 поддельных данных, а затем включить и выключитьTime-slicing
в случае щелчкаCommit items
кнопку для отправки данных, откройте панель производительности Chrome, чтобы записать их производительность, вы получите следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти две цифры, мы можем обнаружить, что сумма до оптимизацииscript
Время выполнения меньше, чем после оптимизации, но, судя по внешнему виду, страница будет зависать примерно на 1,2 секунды после нажатия кнопки отправки перед оптимизацией.После оптимизации страница не будет полностью зависать, но все равно будет оказывать чувство Катона.
Так почему же страница зависает до оптимизации? Поскольку данных, отправленных за один раз, слишком много, внутреннее время выполнения JS слишком велико, что блокирует поток пользовательского интерфейса и приводит к зависанию страницы.
После оптимизации на странице по-прежнему имеет коробку, потому что мы разбиваем данные, составляет 1000 гранулярности. В этом случае компонент рендеринга по-прежнему имеет давление. Мы наблюдаем, что FPS только более чем в десятках, и будет совпадение. Обычно до тех пор, пока FPS страницы достигает 60, страница будет очень гладкой. Если мы превратим размер данных разделения частиц в 100, в основном FPS может достигать 50 или более, хотя рендеринг страницы является гладкой, но завершить 1000 данных Общее время подачи все еще растет.
использоватьTime slicing
Технология позволяет избежать зависания страницы, обычно мы добавляем эффект загрузки при обработке этой трудоемкой задачи, в этом примере мы можем включитьloading animation
, затем отправьте данные. Сравнение показало, что до оптимизации из-за слишком большого количества данных, отправленных за один раз, JS работал в течение длительного времени, блокируя поток пользовательского интерфейса, и эта анимация загрузки не будет отображаться.После оптимизации, потому что мы разделили на несколько временных интервалов для отправки данных один раз. Время выполнения JS сокращено, поэтому анимация загрузки может отображаться.
Здесь следует отметить одну вещь, хотя мы разделили временной интервал, чтобы использовать
requestAnimationFrame
API, но использоватьrequestAnimationFrame
Сама по себе она не может гарантировать полнокадровую работу.requestAnimationFrame
Гарантировано, что соответствующая функция входящего обратного вызова будет выполнена после каждого REDRAW браузера. Для обеспечения полного рама, только время работы JS в одном тике не может превышать 17 мс.
Non-reactive data
Восьмой навык, использованиеNon-reactive data
Для не отвечающих данных вы можете проверить этоОнлайн-пример.
Код до оптимизации выглядит следующим образом:
const data = items.map(
item => ({
id: uid++,
data: item,
vote: 0
})
)
Оптимизированный код выглядит следующим образом:
const data = items.map(
item => optimizeItem(item)
)
function optimizeItem (item) {
const itemData = {
id: uid++,
vote: 0
}
Object.defineProperty(itemData, 'data', {
// Mark as non-reactive
configurable: false,
value: item
})
return itemData
}
Или предыдущий пример, мы сначала нажимаемGenterate items
кнопку, чтобы создать 10 000 поддельных данных, а затем включить и выключитьPartial reactivity
в случае щелчкаCommit items
кнопку для отправки данных, откройте панель производительности Chrome, чтобы записать их производительность, вы получите следующие результаты.
До оптимизации:
Оптимизировано:
Сравнивая эти два рисунка, мы видим, что оптимизированное выполнениеscript
Время значительно меньше, чем до оптимизации, поэтому производительность лучше.
Причина этого различия заключается в том, что когда данные отправляются внутренне, вновь отправленные данные также будут определены как отвечающие по умолчанию.Если податрибут данных находится в форме объекта, он будет рекурсивно Атрибут также отзывчивый, поэтому, когда передается много данных, этот процесс становится трудоемким.
После оптимизации заносим свойства объекта во вновь представленные данныеdata
вручную сталconfigurable
дляfalse
, так что внутреннеwalk
пройти, когдаObject.keys(obj)
Получение массива свойств объекта игнорируетсяdata
, этого не будетdata
это свойствоdefineReactive
,из-заdata
Он указывает на объект, что также уменьшит логику рекурсивного ответа, что эквивалентно уменьшению потери производительности этой части. Чем больше объем данных, тем более очевидным будет эффект от этой оптимизации.
На самом деле существует множество способов оптимизации, например, некоторые данные, которые мы определяем в компоненте, не обязательно должны быть в компоненте.data
определено в. Мы не используем некоторые данные в шаблоне, и нам не нужно отслеживать их изменения, мы просто хотим поделиться данными в контексте компонента, в это время мы можем просто смонтировать данные в экземпляр компонента. .this
на, например:
export default {
created() {
this.scroll = null
},
mounted() {
this.scroll = new BScroll(this.$el)
}
}
Таким образом, мы можем поделиться в контексте компонентаscroll
объект, хотя он и не является реактивным объектом.
Virtual scrolling
Девятый трюк, используйтеVirtual scrolling
Компонент виртуальной прокрутки, вы можете проверить этоОнлайн-пример.
Код компонента до оптимизации выглядит следующим образом:
<div class="items no-v">
<FetchItemViewFunctional
v-for="item of items"
:key="item.id"
:item="item"
@vote="voteItem(item)"
/>
</div>
Оптимизированный код выглядит следующим образом:
<recycle-scroller
class="items"
:items="items"
:item-size="24"
>
<template v-slot="{ item }">
<FetchItemView
:item="item"
@vote="voteItem(item)"
/>
</template>
</recycle-scroller>
Или предыдущий пример, нам нужно включитьView list
, затем нажмитеGenterate items
кнопка для создания 10 000 фрагментов поддельных данных (обратите внимание, что онлайн-пример может создать не более 1000 фрагментов данных, на самом деле 1000 фрагментов данных не могут хорошо отразить эффект оптимизации, поэтому я изменил ограничение исходного кода, запустив его локально , и создали 10 000 единиц данных), а затем отдельно вUnoptimized
а такжеRecycleScroller
в случае щелчкаCommit items
кнопку для отправки данных, прокрутите страницу, откройте панель производительности Chrome, чтобы записать их производительность, и вы получите следующие результаты.
До оптимизации:
Оптимизировано:
Сравнив эти две картинки, мы обнаружили, что в случае отсутствия оптимизации частота кадров из 10 000 фрагментов данных составляет только однозначные числа в случае прокрутки, а в случае отсутствия прокрутки — всего около дюжины. Причина в том, что в неоптимизированной сцене рендерится слишком много DOM, рендеринг сам по себе оказывает большое давление. После оптимизации, даже при 10 000 кусков данных, fps в прокрутке может быть больше 30, а в непрокрутке может достигать 60 полных кадров.
Причина такой разницы в том, что виртуальная прокрутка реализуется за счет рендеринга только DOM в области просмотра, так что общее количество отображаемых DOM очень мало, а естественная производительность будет намного лучше.
Компонент виртуальной прокрутки такжеGuillaume ChauПисьменный, заинтересованные студенты могут изучить егореализация исходного кода. Его основной принцип заключается в прослушивании событий прокрутки, динамическом обновлении элементов DOM, которые необходимо отобразить, и вычислении их смещения в представлении.
Компонент виртуальной прокрутки не обходится без затрат, потому что его необходимо рассчитывать в режиме реального времени в процессе прокрутки, поэтому будет определеннаяscript
стоимость исполнения. Таким образом, если количество данных в списке не очень велико, мы можем использовать обычную прокрутку.
Суммировать
Я надеюсь, что из этой статьи вы сможете узнать о девяти методах оптимизации производительности для Vue.js и применить их к реальным проектам разработки. В дополнение к вышеупомянутым методам существуют другие часто используемые методы оптимизации производительности, такие как отложенная загрузка изображений, отложенная загрузка компонентов и асинхронные компоненты.
Перед оптимизацией производительности нам необходимо проанализировать, где находится узкое место производительности, чтобы адаптироваться к местным условиям. Кроме того, оптимизация производительности требует поддержки данных.Прежде чем выполнять какую-либо оптимизацию производительности, необходимо собрать данные перед оптимизацией, чтобы после оптимизации можно было увидеть эффект оптимизации путем сравнения данных.
Я надеюсь, что в будущем процессе разработки вы будете не только удовлетворены требованиями к реализации, но и будете думать о возможном влиянии на производительность при написании каждой строки кода.
Эта статья была впервые опубликована в публичном аккаунте«Фронтальная частная кухня старого Хуанга», добро пожаловать, чтобы следовать.