← Назад к вопросам

Что такое закэшировать?

1.0 Junior🔥 152 комментариев
#Браузер и сетевые технологии

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое закэшировать?

Определение кэширования

Кэширование - это способ сохранить результат вычисления или запроса, чтобы при следующем обращении к одним и тем же данным вернуть сохранённый результат вместо повторного вычисления или запроса. Это ускоряет работу приложения и снижает нагрузку на ресурсы.

Принцип работы

Первый запрос:
  Запрос -> Вычисление/Загрузка -> Сохранение в кэш -> Возврат результата

Следующий запрос (с кэшем):
  Запрос -> Поиск в кэше -> Найдено! -> Возврат из кэша (быстро)

Следующий запрос (кэш устарел):
  Запрос -> Поиск в кэше -> Не найдено/Устарело -> Вычисление -> Обновление кэша

Виды кэширования в Frontend

1. Кэширование значений в памяти (useMemo)

Сохраняешь результат дорогого вычисления, чтобы не пересчитывать его при каждом рендере:

function Component({ items }) {
  // БЕЗ кэширования - calculateTotal вызывается при каждом рендере
  const total = calculateTotal(items); // Медленно!
  
  // С кэшированием - вычисляется только если items изменился
  const total = useMemo(() => calculateTotal(items), [items]);
  
  return <div>Итого: {total}</div>;
}

function calculateTotal(items) {
  console.log("Вычисляю...");
  return items.reduce((sum, item) => sum + item.price, 0);
}

// При первом рендере: "Вычисляю..." -> результат в кэше
// При втором рендере (items не изменился): результат из кэша, нет console.log
// При третьем рендере (items изменился): "Вычисляю..." -> новый результат

2. Кэширование функций (useCallback)

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

function Parent() {
  const [count, setCount] = useState(0);
  
  // БЕЗ кэширования - новая функция при каждом рендере
  const handleClick = () => setCount(count + 1);
  
  // С кэшированием - одна функция (пока dependencies не изменились)
  const handleClick = useCallback(() => setCount(c => c + 1), []);
  
  return <Child onClick={handleClick} />;
}

// Child компонент с React.memo
const Child = React.memo(({ onClick }) => {
  console.log("Рендер Child");
  return <button onClick={onClick}>Нажми</button>;
});

// БЕЗ useCallback: "Рендер Child" при каждом клике (новая функция = новые props)
// С useCallback: "Рендер Child" только один раз (функция та же)

3. Кэширование HTTP-запросов

Сохраняешь результат сетевого запроса, чтобы не повторять запрос к серверу:

// Без кэширования - при каждом обращении идёт запрос на сервер
function useUser(id) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    fetch(`/api/users/${id}`)
      .then(r => r.json())
      .then(setUser);
  }, [id]);
  
  return user;
}

// Медленно, если один user загружается несколько раз!

// С кэшированием - используешь Map или библиотеку
const userCache = new Map();

function useUser(id) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    // Проверяем кэш
    if (userCache.has(id)) {
      setUser(userCache.get(id));
      return;
    }
    
    fetch(`/api/users/${id}`)
      .then(r => r.json())
      .then(data => {
        userCache.set(id, data); // Сохраняем в кэш
        setUser(data);
      });
  }, [id]);
  
  return user;
}

// Первый запрос: fetch
// Второй запрос (с тем же id): из кэша (быстро!)

4. LocalStorage и SessionStorage

Кэширование на уровне браузера - данные сохраняются между сеансами:

function useLocalCache(key, fetcher) {
  const [data, setData] = useState(() => {
    // При загрузке компонента проверяем localStorage
    const cached = localStorage.getItem(key);
    return cached ? JSON.parse(cached) : null;
  });
  
  useEffect(() => {
    if (!data) {
      fetcher().then(result => {
        setData(result);
        localStorage.setItem(key, JSON.stringify(result)); // Сохраняем
      });
    }
  }, []);
  
  return data;
}

// Использование
function Profile() {
  const user = useLocalCache("user", () => fetch("/api/me").then(r => r.json()));
  return <div>{user?.name}</div>;
}

// При первом посещении: fetch + сохранение в localStorage
// При следующем посещении: данные сразу из localStorage

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

Паттерн с тройным кэшем:

function useFetchWithCache(url) {
  const [data, setData] = useState(() => {
    // 1. Проверяем localStorage (при загрузке)
    const stored = localStorage.getItem(url);
    return stored ? JSON.parse(stored) : null;
  });
  
  useEffect(() => {
    if (data) return; // 2. Если данные есть - ничего не делаем
    
    // 3. Если нет - загружаем
    fetch(url)
      .then(r => r.json())
      .then(result => {
        setData(result);
        localStorage.setItem(url, JSON.stringify(result));
      });
  }, [url, data]);
  
  return data;
}

Кэширование на уровне браузера

Browser Cache (через заголовки HTTP):

Сервер отправляет:
  Cache-Control: max-age=3600
  
Браузер:
  - Сохраняет файл
  - В течение часа не делает новый запрос
  - Показывает кэшированную версию

Service Worker - оффлайн кэширование:

// В Service Worker
self.addEventListener(fetch, (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        // Если в кэше - вернуть из кэша
        if (response) return response;
        // Иначе - сделать запрос
        return fetch(event.request);
      })
  );
});

// Результат: app работает оффлайн, если данные были закэшированы

Когда кэшировать

Кэшируй:

  • Дорогие вычисления (сортировка, фильтрация больших массивов)
  • HTTP-запросы (особенно если один запрос делается несколько раз)
  • Функции, которые передаёшь в качестве props (для React.memo)
  • Результаты парсинга/трансформации данных

Не кэшируй:

  • Простые вычисления (сложение, конкатенация строк)
  • Часто меняющиеся данные (реал-тайм)
  • Большие объекты в памяти (можешь исчерпать RAM)
  • Потенциально устаревшие данные без механизма инвалидации

Проблемы с кэшем

Инвалидация кэша - одна из сложнейших задач:

// Проблема: кэш может содержать устаревшие данные
const cache = new Map();

function updateUser(id, data) {
  fetch(`/api/users/${id}`, { method: "PUT", body: JSON.stringify(data) })
    .then(() => {
      // ЗАБЫЛИ инвалидировать кэш!
      // cache.delete(id);
    });
}

function getUser(id) {
  if (cache.has(id)) {
    return cache.get(id); // Вернём старые данные!
  }
}

Заключение

Кэширование - это переиспользование уже вычисленного результата вместо повторного вычисления. В Frontend это критично для:

  • Производительности: быстрее (из кэша vs новое вычисление)
  • Экономии ресурсов: меньше запросов к серверу
  • Лучшего UX: мгновенная загрузка знакомых данных

Основное правило: кэшируй дорогое, инвалидируй своевременно.

Что такое закэшировать? | PrepBro