Хранилища в браузере
Для хранения данных на стороне клиента есть четыре основных инструмента: localStorage, sessionStorage, cookies и IndexedDB. Они различаются объёмом, сроком жизни и API, но главное, что важно понимать на собеседовании, - кто имеет доступ к данным: только браузер или ещё и сервер.
Главное отличие: кто видит данные
localStorage, sessionStorage и IndexedDB живут только в браузере. Сервер о них ничего не знает - данные никуда не уходят сами по себе. Если их нужно передать на бэкенд, вы делаете это вручную через fetch/XMLHttpRequest.
Cookies - единственное хранилище, связанное с сервером. Браузер автоматически прикрепляет их к каждому HTTP-запросу к этому домену в заголовке Cookie, а сервер устанавливает их через заголовок Set-Cookie. Поэтому работа с cookies (особенно для авторизации) - это обычно изменения на сервере, а не только JS-код. Более того, самые безопасные cookie (HttpOnly) вообще недоступны из JavaScript и управляются исключительно сервером.
Сравнение
| localStorage | sessionStorage | Cookies | IndexedDB | |
|---|---|---|---|---|
| Объём | ~5-10 MB | ~5 MB | ~4 KB на cookie | сотни MB - гигабайты |
| Срок жизни | до явной очистки | до закрытия вкладки | задаётся (expires/max-age) | до явной очистки |
| Область видимости | все вкладки origin | только текущая вкладка | все вкладки origin | все вкладки origin |
| Тип данных | строки | строки | строки | объекты, массивы, Blob, File |
| API | синхронный | синхронный | строка document.cookie | асинхронный, транзакционный |
| Отправляется на сервер | нет | нет | да, автоматически | нет |
| Доступ из JS | да | да | да (если не HttpOnly) | да |
localStorage
Простое key-value хранилище. Данные не имеют срока годности и сохраняются между сессиями, общие для всех вкладок одного origin. API синхронный и хранит только строки - объекты нужно сериализовать.
localStorage.setItem("user", JSON.stringify({ name: "Иван" }))
const user = JSON.parse(localStorage.getItem("user"))
localStorage.removeItem("user")
localStorage.clear()
Между вкладками можно синхронизироваться через событие storage (срабатывает в других вкладках при изменении):
window.addEventListener("storage", (e) => {
if (e.key === "theme") applyTheme(e.newValue)
})
Минусы: синхронный (блокирует поток при больших данных), только строки, доступен из JS - нельзя хранить токены и чувствительные данные (уязвимо к XSS).
sessionStorage
Тот же API, что и у localStorage, но данные изолированы в пределах одной вкладки и удаляются при её закрытии. Подходит для временного состояния: данные многошаговой формы, состояние до перезагрузки.
sessionStorage.setItem("step", "2")
sessionStorage.getItem("step") // "2", но только в этой вкладке
Cookies
Небольшие (~4 KB) строки, которые браузер автоматически отправляет на сервер с каждым запросом. Исторически - основной механизм сессий и аутентификации.
// Установка из JS (доступна только не-HttpOnly cookie)
document.cookie = "theme=dark; max-age=3600; path=/; SameSite=Strict"
console.log(document.cookie) // "theme=dark; lang=ru"
Но для авторизации cookie обычно ставит сервер, чтобы пометить их HttpOnly:
# Ответ сервера
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict; Max-Age=86400
Важные флаги безопасности:
HttpOnly- cookie недоступна из JS (защита от кражи через XSS).Secure- передаётся только по HTTPS.SameSite=Strict/Lax- ограничивает отправку с других сайтов (защита от CSRF).
IndexedDB
Полноценная асинхронная транзакционная NoSQL-база данных в браузере. В отличие от localStorage хранит структурированные данные (объекты, массивы, Blob, File), поддерживает индексы, версионирование схемы и большие объёмы (сотни мегабайт и больше). Используется для офлайн-приложений, PWA и кэша тяжёлых данных.
const req = indexedDB.open("app-db", 1)
req.onupgradeneeded = (e) => {
const db = e.target.result
db.createObjectStore("notes", { keyPath: "id" })
}
req.onsuccess = (e) => {
const db = e.target.result
const tx = db.transaction("notes", "readwrite")
tx.objectStore("notes").put({ id: 1, text: "Привет" })
}
Нативный API многословный и построен на колбэках/событиях, поэтому на практике берут обёртки вроде idb или Dexie.js, дающие промисы:
import { openDB } from "idb"
const db = await openDB("app-db", 1, {
upgrade(db) { db.createObjectStore("notes", { keyPath: "id" }) },
})
await db.put("notes", { id: 1, text: "Привет" })
const note = await db.get("notes", 1)
Что и когда выбирать
- localStorage - настройки интерфейса, тема, некритичный кэш (только строки, немного данных).
- sessionStorage - временное состояние в пределах вкладки (шаги формы).
- Cookies - сессии и аутентификация (
HttpOnlyсо стороны сервера), любые данные, нужные серверу на каждом запросе. - IndexedDB - большие объёмы, структурированные данные, офлайн-режим и PWA.