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

Хранение данных в браузере

Браузер предоставляет несколько способов хранить данные на стороне клиента. Выбор правильного механизма влияет на производительность, безопасность и удобство пользователя.

Cookies

Cookies — самый старый механизм хранения, появившийся в 1994 году. Главная особенность: браузер автоматически отправляет cookies на сервер в заголовке каждого запроса к соответствующему домену.

Ограничения: не более 4 КБ на cookie, не более ~300 cookies на домен. Cookies имеют срок жизни (expires или max-age). Сессионные cookies (без срока) удаляются при закрытии браузера.

Атрибуты безопасности:

  • HttpOnly — cookie недоступна из JavaScript (document.cookie). Защита от XSS
  • Secure — отправляется только по HTTPS
  • SameSite=Strict — не отправляется при переходе с другого сайта. Защита от CSRF
  • SameSite=Lax — отправляется при переходах (ссылки), но не при POST с другого сайта
  • localStorage

    localStorage — хранилище пар ключ/значение. Данные сохраняются навсегда, пока пользователь не очистит их вручную или сайт не удалит их программно.

    Особенности:

  • До 5–10 МБ (зависит от браузера)
  • Данные изолированы по origin (протокол + домен + порт)
  • Синхронный API — блокирует основной поток при больших данных
  • Хранит только строки — объекты нужно сериализовать через JSON
  • sessionStorage

    Аналог localStorage, но данные живут только в рамках текущей вкладки и удаляются при её закрытии. Каждая вкладка имеет свой независимый sessionStorage, даже открытая через Ctrl+T.

    Применение: временные данные формы, состояние многошаговых wizard-форм, данные текущей сессии.

    IndexedDB

    IndexedDB — полноценная NoSQL база данных в браузере. Поддерживает структурированные данные (объекты, Blob, ArrayBuffer), индексы, транзакции и запросы. Асинхронный API — не блокирует основной поток.

    Лимит: от 50 МБ до нескольких ГБ (зависит от доступного места на диске). Браузер может запросить разрешение при больших объёмах.

    Применение: офлайн-приложения, кэш изображений, локальная база данных PWA.

    Сравнение

    | Механизм | Размер | Срок жизни | Доступ | Отправляется на сервер |

    |---|---|---|---|---|

    | Cookies | 4 КБ | Настраиваемый | Sync | Да |

    | localStorage | 5–10 МБ | Навсегда | Sync | Нет |

    | sessionStorage | 5–10 МБ | До закрытия вкладки | Sync | Нет |

    | IndexedDB | 50 МБ+ | Навсегда | Async | Нет |

    Storage Events

    Когда одна вкладка изменяет localStorage, другие вкладки того же origin получают событие storage. Это позволяет синхронизировать состояние между вкладками: выход из аккаунта в одной вкладке автоматически разлогинивает все остальные.

    Важно: событие storage НЕ срабатывает в той же вкладке, которая внесла изменение — только в других.

    Примеры

    Сравнение хранилищ, кэш с истечением срока, события между вкладками

    // localStorage: хранение объектов (нужна сериализация)
    const user = { name: 'Алексей', theme: 'dark', lang: 'ru' }
    localStorage.setItem('user', JSON.stringify(user))
    const savedUser = JSON.parse(localStorage.getItem('user') || '{}')
    console.log('Пользователь:', savedUser.name)
    
    // Кэш с временем жизни на основе localStorage
    function setCacheItem(key, value, ttlSeconds) {
      const item = {
        value,
        expiresAt: Date.now() + ttlSeconds * 1000,
      }
      localStorage.setItem(key, JSON.stringify(item))
    }
    
    function getCacheItem(key) {
      const raw = localStorage.getItem(key)
      if (!raw) return null
      const item = JSON.parse(raw)
      if (Date.now() > item.expiresAt) {
        localStorage.removeItem(key)  // устарело — удаляем
        return null
      }
      return item.value
    }
    
    // Кэшируем на 60 секунд
    setCacheItem('rates', { USD: 90, EUR: 98 }, 60)
    console.log('Из кэша:', getCacheItem('rates'))
    
    // Синхронизация между вкладками через storage event
    window.addEventListener('storage', (event) => {
      console.log('Изменился ключ:', event.key)
      console.log('Старое значение:', event.oldValue)
      console.log('Новое значение:', event.newValue)
      // Например: если ключ 'logout' изменился — перенаправить на страницу входа
      if (event.key === 'logout') window.location.href = '/login'
    })
    
    // Проверяем доступное место (не все браузеры поддерживают)
    if ('storage' in navigator) {
      const { usage, quota } = await navigator.storage.estimate()
      console.log(`Использовано: ${(usage / 1024 / 1024).toFixed(2)} МБ`)
      console.log(`Доступно: ${(quota / 1024 / 1024).toFixed(0)} МБ`)
    }

    Хранение данных в браузере

    Браузер предоставляет несколько способов хранить данные на стороне клиента. Выбор правильного механизма влияет на производительность, безопасность и удобство пользователя.

    Cookies

    Cookies — самый старый механизм хранения, появившийся в 1994 году. Главная особенность: браузер автоматически отправляет cookies на сервер в заголовке каждого запроса к соответствующему домену.

    Ограничения: не более 4 КБ на cookie, не более ~300 cookies на домен. Cookies имеют срок жизни (expires или max-age). Сессионные cookies (без срока) удаляются при закрытии браузера.

    Атрибуты безопасности:

  • HttpOnly — cookie недоступна из JavaScript (document.cookie). Защита от XSS
  • Secure — отправляется только по HTTPS
  • SameSite=Strict — не отправляется при переходе с другого сайта. Защита от CSRF
  • SameSite=Lax — отправляется при переходах (ссылки), но не при POST с другого сайта
  • localStorage

    localStorage — хранилище пар ключ/значение. Данные сохраняются навсегда, пока пользователь не очистит их вручную или сайт не удалит их программно.

    Особенности:

  • До 5–10 МБ (зависит от браузера)
  • Данные изолированы по origin (протокол + домен + порт)
  • Синхронный API — блокирует основной поток при больших данных
  • Хранит только строки — объекты нужно сериализовать через JSON
  • sessionStorage

    Аналог localStorage, но данные живут только в рамках текущей вкладки и удаляются при её закрытии. Каждая вкладка имеет свой независимый sessionStorage, даже открытая через Ctrl+T.

    Применение: временные данные формы, состояние многошаговых wizard-форм, данные текущей сессии.

    IndexedDB

    IndexedDB — полноценная NoSQL база данных в браузере. Поддерживает структурированные данные (объекты, Blob, ArrayBuffer), индексы, транзакции и запросы. Асинхронный API — не блокирует основной поток.

    Лимит: от 50 МБ до нескольких ГБ (зависит от доступного места на диске). Браузер может запросить разрешение при больших объёмах.

    Применение: офлайн-приложения, кэш изображений, локальная база данных PWA.

    Сравнение

    | Механизм | Размер | Срок жизни | Доступ | Отправляется на сервер |

    |---|---|---|---|---|

    | Cookies | 4 КБ | Настраиваемый | Sync | Да |

    | localStorage | 5–10 МБ | Навсегда | Sync | Нет |

    | sessionStorage | 5–10 МБ | До закрытия вкладки | Sync | Нет |

    | IndexedDB | 50 МБ+ | Навсегда | Async | Нет |

    Storage Events

    Когда одна вкладка изменяет localStorage, другие вкладки того же origin получают событие storage. Это позволяет синхронизировать состояние между вкладками: выход из аккаунта в одной вкладке автоматически разлогинивает все остальные.

    Важно: событие storage НЕ срабатывает в той же вкладке, которая внесла изменение — только в других.

    Примеры

    Сравнение хранилищ, кэш с истечением срока, события между вкладками

    // localStorage: хранение объектов (нужна сериализация)
    const user = { name: 'Алексей', theme: 'dark', lang: 'ru' }
    localStorage.setItem('user', JSON.stringify(user))
    const savedUser = JSON.parse(localStorage.getItem('user') || '{}')
    console.log('Пользователь:', savedUser.name)
    
    // Кэш с временем жизни на основе localStorage
    function setCacheItem(key, value, ttlSeconds) {
      const item = {
        value,
        expiresAt: Date.now() + ttlSeconds * 1000,
      }
      localStorage.setItem(key, JSON.stringify(item))
    }
    
    function getCacheItem(key) {
      const raw = localStorage.getItem(key)
      if (!raw) return null
      const item = JSON.parse(raw)
      if (Date.now() > item.expiresAt) {
        localStorage.removeItem(key)  // устарело — удаляем
        return null
      }
      return item.value
    }
    
    // Кэшируем на 60 секунд
    setCacheItem('rates', { USD: 90, EUR: 98 }, 60)
    console.log('Из кэша:', getCacheItem('rates'))
    
    // Синхронизация между вкладками через storage event
    window.addEventListener('storage', (event) => {
      console.log('Изменился ключ:', event.key)
      console.log('Старое значение:', event.oldValue)
      console.log('Новое значение:', event.newValue)
      // Например: если ключ 'logout' изменился — перенаправить на страницу входа
      if (event.key === 'logout') window.location.href = '/login'
    })
    
    // Проверяем доступное место (не все браузеры поддерживают)
    if ('storage' in navigator) {
      const { usage, quota } = await navigator.storage.estimate()
      console.log(`Использовано: ${(usage / 1024 / 1024).toFixed(2)} МБ`)
      console.log(`Доступно: ${(quota / 1024 / 1024).toFixed(0)} МБ`)
    }

    Задание

    Реализуй корзину покупок на основе localStorage. Напиши три функции: addItem(product) — добавляет товар (объект с id, name, price), removeItem(id) — удаляет по id, getCart() — возвращает массив товаров. После каждой операции сохраняй корзину в localStorage.

    Подсказка

    Ключ для localStorage — CART_KEY. getCart() должна возвращать [] если данных нет. addItem добавляет product в массив. removeItem фильтрует по полю id. Не забывай сохранять после каждого изменения через saveCart.

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