Что такое мемоизация и чем она отличается от кеширования?

MiddleJavaScript · Frontend·Обновлено 22 августа 2026
Коротко
Мемоизация — это частный случай кеширования, при котором сохраняются результаты вызова чистой функции по её аргументам, чтобы не пересчитывать их повторно. Кеширование — более широкое понятие: хранение любых данных (не обязательно результатов функций) для ускорения доступа, часто с TTL и внешним хранилищем.

Мемоизация

Мемоизация — техника оптимизации, при которой результат выполнения чистой функции сохраняется в локальной структуре данных (обычно Map или объект) по ключу, построенному из её аргументов. При повторном вызове с теми же аргументами функция не выполняется заново, а возвращается сохранённый результат.

Ключевые свойства:

  • работает только с чистыми функциями (без побочных эффектов, детерминированными);
  • кеш обычно живёт в памяти процесса и привязан к конкретной функции;
  • инвалидация как правило отсутствует — считается, что для одних и тех же входных данных результат никогда не меняется.

Кеширование

Кеширование — более общее понятие: сохранение любых данных (результатов вычислений, ответов API, файлов, HTML-страниц) для ускорения последующего доступа. Кеш может:

  • иметь TTL (время жизни) и явную инвалидацию;
  • находиться вне процесса (Redis, CDN, HTTP-кеш браузера);
  • хранить данные, которые меняются во времени (курс валют, список пользователей);
  • требовать стратегии вытеснения (LRU, LFU) при ограниченном размере.

Главное отличие

Мемоизация — это кеширование, но не наоборот. Мемоизация всегда про результаты функций и привязана к их аргументам как ключу; кеширование — про данные вообще, с более сложным жизненным циклом (TTL, инвалидация, распределённое хранилище).

Пример мемоизации

См. код ниже: функция memoize оборачивает дорогую чистую функцию и кеширует результат по сериализованным аргументам.

Пример кеширования

Запрос к API кешируется на 60 секунд, после чего данные считаются устаревшими и запрашиваются заново — это классическое кеширование с TTL, а не мемоизация.

Где применяется в JS/React

  • useMemo и useCallback в React — мемоизация значений и функций между рендерами по списку зависимостей;
  • мемоизация в алгоритмах динамического программирования (числа Фибоначчи, обход графов);
  • селекторы в Redux (reselect) — мемоизация производных данных из стора.

Подводные камни

  • мемоизация нечистой функции (обращение к Date.now(), случайным числам, внешнему состоянию) даст неверные результаты;
  • кеш мемоизации может расти бесконечно и вызывать утечки памяти, если не ограничивать его размер или не использовать WeakMap для объектных ключей;
  • сериализация сложных аргументов (объекты, массивы) для построения ключа кеша может быть дорогой сама по себе;
  • в отличие от полноценного кеша, мемоизация обычно не учитывает время жизни данных — если исходные данные изменились, а функция формально «чистая» по сигнатуре, результат может устареть.

Что хочет услышать интервьюер

Кандидат чётко разделяет понятия: мемоизация — про результаты чистых функций, кеширование — общее понятие про любые данные

Упоминает, что мемоизация — частный случай кеширования, а не синоним

Знает про инвалидацию и TTL как признак «настоящего» кеша, отсутствующий в базовой мемоизации

Приводит примеры из практики: useMemo/useCallback, reselect, кеш HTTP-запросов

Понимает риски: утечки памяти, некорректная мемоизация нечистых функций

Пример: Простая мемоизация чистой функции

function memoize(fn) {
  const cache = new Map();

  return function (...args) {
    const key = JSON.stringify(args);

    if (cache.has(key)) {
      return cache.get(key);
    }

    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
}

// Дорогая чистая функция
function fib(n) {
  if (n <= 1) return n;
  return fib(n - 1) + fib(n - 2);
}

const memoizedFib = memoize(fib);

memoizedFib(35); // считает честно
memoizedFib(35); // возвращает из кеша мгновенно

Пример: Кеширование с TTL (не мемоизация)

const cache = new Map();
const TTL_MS = 60_000;

async function getUserWithCache(id) {
  const cached = cache.get(id);

  // Данные считаются устаревшими через TTL — этого нет в чистой мемоизации
  if (cached && Date.now() - cached.timestamp < TTL_MS) {
    return cached.data;
  }

  const data = await fetch(`/api/users/${id}`).then((r) => r.json());
  cache.set(id, { data, timestamp: Date.now() });
  return data;
}

Типичные ошибки

Используют термины как полные синонимы, не видя разницы в объёме понятий

Пытаются мемоизировать функции с побочными эффектами или недетерминированным поведением

Не учитывают рост памяти при неограниченном кеше мемоизации

Забывают, что ключ кеша должен учитывать все аргументы, а не только часть

Путают мемоизацию на уровне рендера (useMemo) с постоянным кешированием между сессиями

Лучшие курсы по теме

изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Feature-Sliced Design

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.5
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее