\n// Всегда будет переузнать старый кеш\n\n// Хорошо\n\n// С изменением кода меняется hash, новый файл загружается\n```\n\n**2. Используйте стратегии в зависимости от типа:**\n\n```javascript\n// HTML — no-cache, всегда проверять\nCache-Control: no-cache\n\n// CSS/JS — long-term с versioning\nCache-Control: public, max-age=31536000, immutable\n\n// API responses — короткий кеш\nCache-Control: private, max-age=300, must-revalidate\n```\n\n**3. Тестируйте кеширование:**\n\n```javascript\n// DevTools -> Network -> Disable cache\n// Или в коде\nfetch(url, { cache: 'no-store' }); // Всегда свежее\nfetch(url, { cache: 'force-cache' }); // Только кеш\nfetch(url, { cache: 'default' }); // Стандартное поведение\n```\n\n### Итог\n\nБраузер решает кешировать на основе:\n- **Cache-Control заголовков** от сервера (основной механизм)\n- **ETag и Last-Modified** для проверки валидности\n- **Service Workers** для гибкого контроля\n- **Heuristic expiration** (редко, если заголовков нет)\n\nПравильное кеширование — это один из главных факторов производительности веба.","dateCreated":"2026-04-02T22:21:50.296392","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Как браузер понимает когда нужно что-либо закэшировать?

2.0 Middle🔥 161 комментариев
#Браузер и сетевые технологии

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

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

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

Как браузер управляет кешированием ресурсов

Браузер использует HTTP заголовки кеша и встроенные эвристики для определения того, какие ресурсы и как долго кешировать. Это критически важно для производительности веба.

HTTP Cache Headers

Основной механизм кеширования — Cache-Control заголовок:

// На сервере (Node.js/Express пример)
app.get('/api/data', (req, res) => {
  // Не кешировать — всегда свежие данные
  res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
  res.json(data);
});

app.get('/images/logo.png', (req, res) => {
  // Кешировать на 1 год (для static assets с version hash)
  res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
  res.sendFile('logo.png');
});

app.get('/api/profile', (req, res) => {
  // Кешировать на 5 минут, затем проверить валидность
  res.setHeader('Cache-Control', 'private, max-age=300, must-revalidate');
  res.json(profile);
});

Директивы Cache-Control

max-age — основной параметр, указывает время жизни в секундах:

// Cache-Control: max-age=3600
// Ресурс свежий 1 час (3600 сек)
// После истечения — браузер должен переспросить сервер

// Cache-Control: max-age=0
// Сразу устаревший, нужна перепроверка

public vs private:

// Cache-Control: public
// Могут кешировать браузер И промежуточные кеши (CDN, proxies)
res.setHeader('Cache-Control', 'public, max-age=3600');

// Cache-Control: private
// Кешируется только в браузере, не на промежуточных кешах
res.setHeader('Cache-Control', 'private, max-age=300');

no-cache vs no-store:

// no-cache — Кешируется, но перепроверяется всегда
// Браузер отправит If-Modified-Since или ETag
res.setHeader('Cache-Control', 'no-cache');

// no-store — Не кешировать вообще
// Ресурс каждый раз загружается с сервера
res.setHeader('Cache-Control', 'no-store');

immutable — Ресурс никогда не изменится:

// Используется для versioned assets
// /images/logo.abc123def456.png — hash в имени гарантирует уникальность
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');

Механизм Conditional Requests

Когда max-age истекает, браузер проверяет, изменился ли ресурс:

// Сервер отправляет в первый раз:
res.setHeader('ETag', '"abc123"');
res.setHeader('Last-Modified', 'Mon, 01 Jan 2024 00:00:00 GMT');
res.setHeader('Cache-Control', 'max-age=3600');

// Браузер кеширует и ETag
// Через час отправляет условный запрос:
// If-None-Match: "abc123"
// If-Modified-Since: Mon, 01 Jan 2024 00:00:00 GMT

// Если сервер вернёт 304 Not Modified — кеш переиспользуется
if (req.headers['if-none-match'] === currentETag) {
  res.status(304).end(); // Not Modified
} else {
  res.status(200).json(data);
}

Expires заголовок (deprecated)

// Старый способ (все ещё поддерживается)
res.setHeader('Expires', 'Wed, 01 Apr 2026 12:00:00 GMT');

// Но Cache-Control имеет приоритет и рекомендуется
res.setHeader('Cache-Control', 'max-age=86400');
res.setHeader('Expires', 'Wed, 01 Apr 2026 12:00:00 GMT'); // Игнорируется

Service Workers и кеширование

Для более гибкого контроля используется Service Worker API:

// service-worker.js
self.addEventListener('fetch', (event) => {
  const { request } = event;
  
  // Кеширование "cache first" стратегия
  event.respondWith(
    caches.match(request).then((response) => {
      if (response) return response;
      
      return fetch(request).then((response) => {
        if (!response || response.status !== 200) {
          return response;
        }
        
        // Кешируем только успешные ответы
        const responseToCache = response.clone();
        caches.open('v1').then((cache) => {
          cache.put(request, responseToCache);
        });
        
        return response;
      });
    }).catch(() => caches.match('/offline.html'))
  );
});

Стратегии кеширования

Cache First — для static assets:

// Сначала ищем в кеше, если нет — запрашиваем сервер
if (cache.has(url)) return cache.get(url);
return fetch(url).then(response => {
  cache.set(url, response);
  return response;
});

Network First — для динамических данных:

// Сначала идём на сервер, если не доступен — кеш
return fetch(url)
  .then(response => {
    cache.set(url, response);
    return response;
  })
  .catch(() => cache.get(url));

Stale While Revalidate — лучшее из обоих миров:

// Возвращаем кеш сразу, затем обновляем в фоне
const cached = cache.get(url);
if (cached) {
  fetch(url).then(response => cache.set(url, response));
  return cached;
}
return fetch(url).then(response => {
  cache.set(url, response);
  return response;
});

Эту стратегию можно выразить через заголовки:

res.setHeader('Cache-Control', 'public, max-age=300, stale-while-revalidate=86400');
// Свежий 5 минут, затем можно использовать устаревший до 1 дня

Инструменты разработчика

В DevTools -> Network tab видно:

Size: from disk cache (синий) — из памяти браузера
Size: from memory cache (зелёный) — из оперативной памяти
Size: 1.2 KB (красный) — загружено с сервера
200 (сервер) — свежий ответ
304 Not Modified — не изменился, кеш валидный

Best Practices

1. Версионируйте assets:

// Плохо
<script src="/app.js"></script>
// Всегда будет переузнать старый кеш

// Хорошо
<script src="/app.abc123def456.js"></script>
// С изменением кода меняется hash, новый файл загружается

2. Используйте стратегии в зависимости от типа:

// HTML — no-cache, всегда проверять
Cache-Control: no-cache

// CSS/JS — long-term с versioning
Cache-Control: public, max-age=31536000, immutable

// API responses — короткий кеш
Cache-Control: private, max-age=300, must-revalidate

3. Тестируйте кеширование:

// DevTools -> Network -> Disable cache
// Или в коде
fetch(url, { cache: 'no-store' }); // Всегда свежее
fetch(url, { cache: 'force-cache' }); // Только кеш
fetch(url, { cache: 'default' }); // Стандартное поведение

Итог

Браузер решает кешировать на основе:

  • Cache-Control заголовков от сервера (основной механизм)
  • ETag и Last-Modified для проверки валидности
  • Service Workers для гибкого контроля
  • Heuristic expiration (редко, если заголовков нет)

Правильное кеширование — это один из главных факторов производительности веба.