Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке мемоізація і коли вона шкодить більше, ніж допомагає?

Мемоізація - кешування результату функції за її аргументами: повторний виклик з тими самими аргументами повертає збережений результат замість повторного обчислення.

function memoize(fn) {
  const cache = new Map();
  return (arg) => {
    if (!cache.has(arg)) {
      cache.set(arg, fn(arg));
    }
    return cache.get(arg);
  };
}

const slowSquare = (n) => { /* важке обчислення */ return n * n; };
const fastSquare = memoize(slowSquare);

Кеш живе в замиканні - прямо до нього ніхто не дістанеться.

Умови, за яких мемоізація коректна:

  • функція чиста: результат залежить лише від аргументів і не має побічних ефектів. Мемоізувати getCurrentUser() чи функцію з Date.now() всередині - отримати застарілі дані;
  • аргументи можна порівняти як ключ. Для примітивів - просто. Для об'єктів Map порівнює за посиланням: два однакові за вмістом об'єкти - два різні ключі. Для кількох аргументів ключ доводиться будувати (JSON.stringify(args)), а це має свою ціну.

Коли мемоізація шкодить:

  • дешеві функції. Перевірка кешу, побудова ключа й зберігання можуть коштувати більше, ніж саме обчислення;
  • рідкісні повтори. Якщо аргументи майже завжди нові, кеш лише росте;
  • пам'ять. Кеш без обмеження - витік. Для довгоживучих сторінок потрібне обмеження розміру (LRU) або WeakMap, якщо ключ - об'єкт, і запис має зникати разом з ним;
  • змінні аргументи. Якщо об'єкт-аргумент змінили «на місці», посилання те саме - кеш поверне результат для старого вмісту.

Мемоізація у фреймворках:

  • Vue computed - мемоізоване значення, що перераховується лише при зміні реактивних залежностей;
  • React useMemo, useCallback, memo - зберігають значення чи функцію між рендерами. Найчастіша помилка - обгортати ними все підряд: порівняння залежностей теж коштує, а код стає складнішим. Їх застосовують при виміряній проблемі продуктивності чи для стабільних посилань, від яких залежать інші ефекти;
  • у Laravel аналог - once(), що мемоізує результат у межах запиту.

Класичний приклад виправданої мемоізації - рекурсія з перекриттям підзадач (числа Фібоначчі, динамічне програмування): без кешу експоненційна складність, з кешем - лінійна.

Докладніше в документації: Мемоізація

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання