Браузер предоставляет несколько способов хранить данные на стороне клиента. Выбор правильного механизма влияет на производительность, безопасность и удобство пользователя.
Cookies — самый старый механизм хранения, появившийся в 1994 году. Главная особенность: браузер автоматически отправляет cookies на сервер в заголовке каждого запроса к соответствующему домену.
Ограничения: не более 4 КБ на cookie, не более ~300 cookies на домен. Cookies имеют срок жизни (expires или max-age). Сессионные cookies (без срока) удаляются при закрытии браузера.
Атрибуты безопасности:
document.cookie). Защита от XSSlocalStorage — хранилище пар ключ/значение. Данные сохраняются навсегда, пока пользователь не очистит их вручную или сайт не удалит их программно.
Особенности:
Аналог localStorage, но данные живут только в рамках текущей вкладки и удаляются при её закрытии. Каждая вкладка имеет свой независимый sessionStorage, даже открытая через Ctrl+T.
Применение: временные данные формы, состояние многошаговых wizard-форм, данные текущей сессии.
IndexedDB — полноценная NoSQL база данных в браузере. Поддерживает структурированные данные (объекты, Blob, ArrayBuffer), индексы, транзакции и запросы. Асинхронный API — не блокирует основной поток.
Лимит: от 50 МБ до нескольких ГБ (зависит от доступного места на диске). Браузер может запросить разрешение при больших объёмах.
Применение: офлайн-приложения, кэш изображений, локальная база данных PWA.
| Механизм | Размер | Срок жизни | Доступ | Отправляется на сервер |
|---|---|---|---|---|
| Cookies | 4 КБ | Настраиваемый | Sync | Да |
| localStorage | 5–10 МБ | Навсегда | Sync | Нет |
| sessionStorage | 5–10 МБ | До закрытия вкладки | Sync | Нет |
| IndexedDB | 50 МБ+ | Навсегда | Async | Нет |
Когда одна вкладка изменяет 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 — самый старый механизм хранения, появившийся в 1994 году. Главная особенность: браузер автоматически отправляет cookies на сервер в заголовке каждого запроса к соответствующему домену.
Ограничения: не более 4 КБ на cookie, не более ~300 cookies на домен. Cookies имеют срок жизни (expires или max-age). Сессионные cookies (без срока) удаляются при закрытии браузера.
Атрибуты безопасности:
document.cookie). Защита от XSSlocalStorage — хранилище пар ключ/значение. Данные сохраняются навсегда, пока пользователь не очистит их вручную или сайт не удалит их программно.
Особенности:
Аналог localStorage, но данные живут только в рамках текущей вкладки и удаляются при её закрытии. Каждая вкладка имеет свой независимый sessionStorage, даже открытая через Ctrl+T.
Применение: временные данные формы, состояние многошаговых wizard-форм, данные текущей сессии.
IndexedDB — полноценная NoSQL база данных в браузере. Поддерживает структурированные данные (объекты, Blob, ArrayBuffer), индексы, транзакции и запросы. Асинхронный API — не блокирует основной поток.
Лимит: от 50 МБ до нескольких ГБ (зависит от доступного места на диске). Браузер может запросить разрешение при больших объёмах.
Применение: офлайн-приложения, кэш изображений, локальная база данных PWA.
| Механизм | Размер | Срок жизни | Доступ | Отправляется на сервер |
|---|---|---|---|---|
| Cookies | 4 КБ | Настраиваемый | Sync | Да |
| localStorage | 5–10 МБ | Навсегда | Sync | Нет |
| sessionStorage | 5–10 МБ | До закрытия вкладки | Sync | Нет |
| IndexedDB | 50 МБ+ | Навсегда | Async | Нет |
Когда одна вкладка изменяет 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.