Memoización


¿Qué es la Memoización?

La memoización es una técnica de optimización que consiste en guardar el resultado de una función la primera vez que se ejecuta con unos argumentos concretos, para devolver directamente ese resultado si se vuelve a llamar con los mismos parámetros, sin recalcular nada.

¿Para qué se utiliza?

La memoización se usa para:

  • Acelerar funciones con cálculos pesados que se llaman repetidamente con los mismos inputs.
  • Optimizar algoritmos recursivos como Fibonacci o rutas en grafos.
  • Evitar rerenders innecesarios en React con useMemo y useCallback.
  • Reducir llamadas a APIs o bases de datos con los mismos parámetros.
  • Mejorar el rendimiento percibido sin cambiar la lógica del programa.

¿Cómo funciona?

Piensa en la memoización como los apuntes de un estudiante. La primera vez que resuelve un problema, lo trabaja desde cero y apunta el resultado. La segunda vez que aparece el mismo problema, mira sus apuntes y listo — resultado instantáneo. La función hace exactamente lo mismo: consulta su “cuaderno de respuestas” antes de calcular.

Ejemplo: Implementación manual de memoización

// Sin memoización: recalcula siempre (exponencial en recursividad)
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// fibonacci(40) tarda varios segundos — calcula lo mismo millones de veces

// Con memoización: guarda cada resultado
function memoize(fn) {
  const cache = new Map();

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

    if (cache.has(clave)) {
      return cache.get(clave); // ← resultado instantáneo
    }

    const resultado = fn.apply(this, args);
    cache.set(clave, resultado);
    return resultado;
  };
}

const fibMemo = memoize(function fibonacci(n) {
  if (n <= 1) return n;
  return fibMemo(n - 1) + fibMemo(n - 2);
});

console.log(fibMemo(40)); // Instantáneo

Ejemplo: useMemo en React

import { useMemo, useState } from 'react';

function ListaFiltrada({ items }) {
  const [filtro, setFiltro] = useState('');

  // Sin useMemo: recalcula el filtrado en CADA render, incluso si no cambia nada
  // const itemsFiltrados = items.filter(i => i.nombre.includes(filtro));

  // Con useMemo: solo recalcula cuando cambia 'items' o 'filtro'
  const itemsFiltrados = useMemo(
    () => items.filter((i) => i.nombre.includes(filtro)),
    [items, filtro] // ← dependencias que activan el recálculo
  );

  return (
    <ul>
      {itemsFiltrados.map((item) => (
        <li key={item.id}>{item.nombre}</li>
      ))}
    </ul>
  );
}

La memoización no es gratis: consume memoria para almacenar los resultados. Úsala cuando el coste del cálculo supera claramente el coste de almacenar el resultado — especialmente en funciones puras con inputs repetitivos.