Кэширование и мемоизация звучат как бесплатная оптимизация. Мы думаем: «Раз вычисление можно не делать повторно, значит всегда лучше закэшировать». Но это опасное заблуждение. Если кэшировать без меры, приложение начинает засорять память и работать хуже, а не лучше.
🚨 Как мы засоряем память
Представьте, что вы храните в памяти результаты всех вычислений. Старые данные не удаляются, новые постоянно добавляются. В итоге кэш разрастается до сотен мегабайт. На слабых устройствах это выливается во фризы или даже падение.
Был реальный кейс: разработчик решил «оптимизировать» React-страницу и мемоизировал каждый UI-компонент. На странице их было сотни. В итоге выигрыш оказался мизерным, а память улетела в космос. Сам процесс мемоизации стал дороже, чем пересчёт. Правильнее было бы мемоизировать целую форму или контейнер, где решение о перерисовке действительно экономит ресурсы.
❌ Пример бессмысленной мемоизации
function add(a, b) {
return a + b;
}
// кто-то решил мемоизировать даже это
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = args.join(',');
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
const memoAdd = memoize(add);
console.log(memoAdd(2, 3)); // 5
console.log(memoAdd(2, 3)); // 5 из кэша (но толку?)
Сложение и так работает за наносекунды. Хранить результаты в памяти бессмысленно — найти их в Map будет дольше.
✅ Пример, где кэш оправдан
Тяжёлые операции, например парсинг или генерация отчётов.
function heavyComputation(key) {
// имитация дорогой операции
for (let i = 0; i < 1e7; i++) {}
return `Result for ${key}`;
}
Если вызывать её часто с одними и теми же данными, кэш реально ускоряет работу. Но нужен лимит. Самый популярный вариант — LRU Cache (Least Recently Used).
import LRU from 'lru-cache';
const cache = new LRU({ max: 100 }); // максимум 100 элементов
function getData(key) {
if (cache.has(key)) {
return cache.get(key);
}
const result = heavyComputation(key);
cache.set(key, result);
return result;
}
console.log(getData("a")); // долго
console.log(getData("a")); // быстро, из кэша
Теперь кэш не растёт бесконечно. Когда хранилище достигает 100 элементов, старые записи выбрасываются.
🔧 Пример из UI
Вместо того чтобы мемоизировать каждый компонент по отдельности:
const MemoButton = React.memo(Button);
const MemoInput = React.memo(Input);
const MemoLabel = React.memo(Label);
Лучше мемоизировать контейнер, внутри которого они все живут:
const Form = ({ fields, onSubmit }) => {
return (
<form onSubmit={onSubmit}>
{fields.map((f) => (
<Input key={f.id} {...f} />
))}
<button type="submit">Submit</button>
</form>
);
};
// мемоизируем целиком форму
export default React.memo(Form);
Так вы экономите не на «каждой кнопке», а на всей форме сразу. Это дешевле и эффективнее.
Кэш — это инструмент, а не магическая палочка. Он действительно помогает на тяжёлых вычислениях и часто используемых данных. Но хранить всё подряд — значит засорять память. Лёгкие операции всегда лучше пересчитать заново. А в UI выгоднее мемоизировать крупные контейнеры, а не каждую мелочь.
💡Правило простое: если сомневаешься — лучше пересчитай, чем закэшируй навсегда.
#оптимизации #react #frontend #память #memo #кеширование