← Браузер/Кеширование в браузере#180 из 383← ПредыдущийСледующий →+20 XP
Полезно по теме:Гайд: как учить JavaScriptПрактика: async и сетьТермин: Event LoopТермин: Core Web Vitals

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

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

HTTP-кеш: Cache-Control

Сервер управляет кешированием через заголовок Cache-Control. Основные директивы:

`max-age=seconds` — ресурс актуален в течение указанного времени. Например, max-age=31536000 кеширует на год. Браузер не делает запрос к серверу, пока время не истекло.

`no-cache` — кешировать нельзя без проверки. При каждом запросе браузер отправляет условный запрос к серверу. Если ресурс не изменился, сервер отвечает 304 Not Modified без тела — экономия трафика.

`no-store` — не кешировать вообще. Каждый раз полный запрос и полный ответ. Используется для чувствительных данных.

`public` — ресурс можно кешировать на CDN-узлах и прокси-серверах.

`private` — только в кеше конкретного пользователя, не на CDN.

`immutable` — ресурс никогда не изменится. Браузер не будет проверять его актуальность. Используется с хешированными именами файлов.

Валидация кеша: ETag и Last-Modified

При условном запросе браузер отправляет заголовки:

  • If-None-Match: "abc123" — если ETag не изменился, сервер отвечает 304
  • If-Modified-Since: Thu, 01 Jan 2025 00:00:00 GMT — если файл не менялся, сервер отвечает 304
  • Ответ 304 не содержит тела — это экономит трафик при большом количестве ресурсов.

    Cache Busting (сброс кеша)

    Если файл меняется при каждом деплое, нужно принудительно сбросить кеш у пользователей. Стандартное решение — хешированные имена файлов: app.a3f2b1c.js вместо app.js. При каждом изменении файла его хеш меняется, и браузер загружает новую версию. При этом неизменившиеся файлы сохраняют старые хеши и остаются в кеше.

    Service Worker Cache API

    Service Worker — это скрипт, который работает в фоне браузера, перехватывает сетевые запросы и отвечает из кеша. Cache API позволяет программно управлять кешем:

    caches.open('v1')           // открыть (или создать) именованный кеш
    cache.put(url, response)   // сохранить ответ
    cache.match(url)           // найти в кеше
    cache.delete(url)          // удалить запись
    caches.delete('v1')        // удалить весь кеш

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

  • Cache First — сначала кеш, при промахе — сеть. Для статики.
  • Network First — сначала сеть, при ошибке — кеш. Для API-запросов.
  • Stale While Revalidate — отдать из кеша немедленно, обновить в фоне.
  • Проверка источника ресурса

    PerformanceResourceTiming позволяет определить, откуда пришёл ресурс:

  • transferSize === 0 — ресурс из кеша браузера (disk cache или memory cache)
  • transferSize > 0 && encodedBodySize > 0 — загружен с сервера
  • transferSize > 0 && encodedBodySize === 0 — сервер ответил 304 (revalidation)
  • Примеры

    Cache API, проверка источника ресурсов через Resource Timing

    // Cache API — программное кеширование (обычно используется в Service Worker)
    // Открываем именованный кеш
    const cache = await caches.open('api-cache-v1')
    
    // Кешируем запрос вручную
    async function fetchWithCache(url) {
      // Ищем в кеше
      const cached = await cache.match(url)
      if (cached) {
        console.log('Из кеша:', url)
        return cached.json()
      }
    
      // Нет в кеше — загружаем с сервера
      const response = await fetch(url)
      // Клонируем ответ: тело можно прочитать только раз
      cache.put(url, response.clone())
      console.log('С сервера:', url)
      return response.json()
    }
    
    const data = await fetchWithCache('https://jsonplaceholder.typicode.com/posts/1')
    console.log('Данные:', data.title)
    
    // Повторный вызов — уже из кеша
    const dataCached = await fetchWithCache('https://jsonplaceholder.typicode.com/posts/1')
    
    // Проверяем источник ресурсов через Resource Timing
    window.addEventListener('load', () => {
      const resources = performance.getEntriesByType('resource')
      resources.forEach(entry => {
        let source
        if (entry.transferSize === 0) {
          source = 'кеш браузера'  // disk/memory cache
        } else if (entry.encodedBodySize === 0) {
          source = 'сервер (304 Not Modified)'
        } else {
          source = `сервер (${entry.transferSize} байт)`
        }
        console.log(`${entry.name.split('/').pop()}: ${source}`)
      })
    })

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

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

    HTTP-кеш: Cache-Control

    Сервер управляет кешированием через заголовок Cache-Control. Основные директивы:

    `max-age=seconds` — ресурс актуален в течение указанного времени. Например, max-age=31536000 кеширует на год. Браузер не делает запрос к серверу, пока время не истекло.

    `no-cache` — кешировать нельзя без проверки. При каждом запросе браузер отправляет условный запрос к серверу. Если ресурс не изменился, сервер отвечает 304 Not Modified без тела — экономия трафика.

    `no-store` — не кешировать вообще. Каждый раз полный запрос и полный ответ. Используется для чувствительных данных.

    `public` — ресурс можно кешировать на CDN-узлах и прокси-серверах.

    `private` — только в кеше конкретного пользователя, не на CDN.

    `immutable` — ресурс никогда не изменится. Браузер не будет проверять его актуальность. Используется с хешированными именами файлов.

    Валидация кеша: ETag и Last-Modified

    При условном запросе браузер отправляет заголовки:

  • If-None-Match: "abc123" — если ETag не изменился, сервер отвечает 304
  • If-Modified-Since: Thu, 01 Jan 2025 00:00:00 GMT — если файл не менялся, сервер отвечает 304
  • Ответ 304 не содержит тела — это экономит трафик при большом количестве ресурсов.

    Cache Busting (сброс кеша)

    Если файл меняется при каждом деплое, нужно принудительно сбросить кеш у пользователей. Стандартное решение — хешированные имена файлов: app.a3f2b1c.js вместо app.js. При каждом изменении файла его хеш меняется, и браузер загружает новую версию. При этом неизменившиеся файлы сохраняют старые хеши и остаются в кеше.

    Service Worker Cache API

    Service Worker — это скрипт, который работает в фоне браузера, перехватывает сетевые запросы и отвечает из кеша. Cache API позволяет программно управлять кешем:

    caches.open('v1')           // открыть (или создать) именованный кеш
    cache.put(url, response)   // сохранить ответ
    cache.match(url)           // найти в кеше
    cache.delete(url)          // удалить запись
    caches.delete('v1')        // удалить весь кеш

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

  • Cache First — сначала кеш, при промахе — сеть. Для статики.
  • Network First — сначала сеть, при ошибке — кеш. Для API-запросов.
  • Stale While Revalidate — отдать из кеша немедленно, обновить в фоне.
  • Проверка источника ресурса

    PerformanceResourceTiming позволяет определить, откуда пришёл ресурс:

  • transferSize === 0 — ресурс из кеша браузера (disk cache или memory cache)
  • transferSize > 0 && encodedBodySize > 0 — загружен с сервера
  • transferSize > 0 && encodedBodySize === 0 — сервер ответил 304 (revalidation)
  • Примеры

    Cache API, проверка источника ресурсов через Resource Timing

    // Cache API — программное кеширование (обычно используется в Service Worker)
    // Открываем именованный кеш
    const cache = await caches.open('api-cache-v1')
    
    // Кешируем запрос вручную
    async function fetchWithCache(url) {
      // Ищем в кеше
      const cached = await cache.match(url)
      if (cached) {
        console.log('Из кеша:', url)
        return cached.json()
      }
    
      // Нет в кеше — загружаем с сервера
      const response = await fetch(url)
      // Клонируем ответ: тело можно прочитать только раз
      cache.put(url, response.clone())
      console.log('С сервера:', url)
      return response.json()
    }
    
    const data = await fetchWithCache('https://jsonplaceholder.typicode.com/posts/1')
    console.log('Данные:', data.title)
    
    // Повторный вызов — уже из кеша
    const dataCached = await fetchWithCache('https://jsonplaceholder.typicode.com/posts/1')
    
    // Проверяем источник ресурсов через Resource Timing
    window.addEventListener('load', () => {
      const resources = performance.getEntriesByType('resource')
      resources.forEach(entry => {
        let source
        if (entry.transferSize === 0) {
          source = 'кеш браузера'  // disk/memory cache
        } else if (entry.encodedBodySize === 0) {
          source = 'сервер (304 Not Modified)'
        } else {
          source = `сервер (${entry.transferSize} байт)`
        }
        console.log(`${entry.name.split('/').pop()}: ${source}`)
      })
    })

    Задание

    Реализуй класс RequestCache, который кеширует fetch-запросы в Map. Методы: get(url) — возвращает данные из кеша или загружает и кеширует. clear() — очищает весь кеш. has(url) — проверяет, есть ли URL в кеше. Повторный вызов get() для одного URL не должен делать новый запрос.

    Подсказка

    Используй Map — он имеет методы has(), get(), set(), clear(). В методе get() сначала проверь this.cache.has(url), если есть — верни this.cache.get(url). Если нет — загрузи, сохрани через this.cache.set(url, data) и верни data.

    Загружаем среду выполнения...
    Загружаем AI-помощника...