В Vue.js computed свойства представляют собой реактивные
вычисляемые значения, которые зависят от состояния компонента. Основная
особенность computed — кэширование
результатов. Это означает, что вычисление свойства выполняется
только тогда, когда изменяются его зависимости. При повторном доступе к
свойству без изменений зависимостей возвращается ранее вычисленное
значение. Кэширование повышает производительность, особенно при сложных
вычислениях.
Ленивая и мемоизированная оценка
computed свойства вычисляются по запросу. Они не
выполняются при каждом рендере компонента, а только тогда, когда доступ
к свойству фактически необходим. Если зависимые реактивные свойства
(data или другие computed) не изменились, Vue
возвращает сохранённое значение, избегая повторных вычислений.
Отслеживание зависимостей Vue автоматически
отслеживает, какие реактивные свойства используются внутри
computed. Если какая-либо зависимость изменяется, Vue
помечает computed как “грязное” (dirty), и при
следующем обращении вычисление выполняется заново.
Кэширование по компоненту Каждое
computed свойство кэшируется в рамках конкретного
экземпляра компонента. Разные экземпляры компонента имеют свои отдельные
кэши, что гарантирует независимость состояния.
computed
свойстваimport { defineComponent, ref, computed } from 'vue';
export default defineComponent({
setup() {
const numbers = ref([1, 2, 3, 4]);
const sum = computed(() => {
console.log('Вычисляем сумму');
return numbers.value.reduce((acc, n) => acc + n, 0);
});
return { numbers, sum };
}
});
В этом примере sum будет вычислено только при первом
доступе. Если numbers не меняется, последующие обращения к
sum не вызовут повторного вызова функции
reduce. Консоль выведет сообщение только при фактическом
пересчёте.
Vue Test Utils предоставляет инструменты для монтирования компонентов
и проверки их реактивного поведения. Для проверки кэширования
computed свойств важно убедиться, что функция вычисления
вызывается корректное количество раз при изменении зависимостей.
import { mount } from '@vue/test-utils';
import SumComponent from '@/components/SumComponent.vue';
describe('SumComponent', () => {
it('должно кэшировать computed свойство', async () => {
const wrapper = mount(SumComponent);
// Первый доступ к computed, функция вычисляется
expect(wrapper.vm.sum).toBe(10);
// Повторный доступ без изменения зависимостей, функция не вызывается
expect(wrapper.vm.sum).toBe(10);
});
});
it('пересчитывает computed при изменении зависимостей', async () => {
const wrapper = mount(SumComponent);
wrapper.vm.numbers.push(5);
// Используем nextTick для ожидания реактивного обновления
await wrapper.vm.$nextTick();
expect(wrapper.vm.sum).toBe(15);
});
Здесь важно понимать, что computed кэширует результаты
только до изменения зависимостей. После изменения
numbers свойство sum помечается как “грязное”
и вычисляется заново.
Для глубокого тестирования кэширования полезно отслеживать
фактические вызовы функций, используемых внутри computed. В
Jest можно использовать jest.fn():
import { mount } from '@vue/test-utils';
import { ref, computed, defineComponent } from 'vue';
const spyFn = jest.fn(() => 42);
const TestComponent = defineComponent({
setup() {
const value = ref(1);
const computedValue = computed(() => spyFn(value.value));
return { value, computedValue };
}
});
describe('TestComponent', () => {
it('вызывает функцию computed только при необходимости', () => {
const wrapper = mount(TestComponent);
// Первый доступ вызывает функцию
wrapper.vm.computedValue;
expect(spyFn).toHaveBeenCalledTimes(1);
// Повторный доступ без изменений зависимостей не вызывает функцию
wrapper.vm.computedValue;
expect(spyFn).toHaveBeenCalledTimes(1);
// Изменение зависимости вызывает повторный вызов
wrapper.vm.value = 2;
wrapper.vm.computedValue;
expect(spyFn).toHaveBeenCalledTimes(2);
});
});
Такой подход позволяет точно контролировать поведение кэширования и убедиться, что Vue не выполняет лишние вычисления.
computed определяется
через функцию computed, кэширование работает на уровне
возвращаемого реактивного свойства.computed определяется в
объекте computed, кэширование аналогично, но Vue
отслеживает зависимости автоматически на уровне экземпляра.nextTick после изменения зависимых
реактивных свойств, чтобы убедиться, что Vue завершил реактивное
обновление.computed, чтобы
проверять фактическое число вызовов.Кэширование computed свойств снижает нагрузку на
рендеринг и вычисления, особенно при больших данных или сложных
операциях. Тестирование кэширования обеспечивает правильное
использование этих преимуществ и предотвращает ненужные повторные
вычисления.