HTML

Чем localStorage отличается от sessionStorage и cookies?

Хранилища в браузере

Для хранения данных на стороне клиента есть четыре основных инструмента: localStorage, sessionStorage, cookies и IndexedDB. Они различаются объёмом, сроком жизни и API, но главное, что важно понимать на собеседовании, - кто имеет доступ к данным: только браузер или ещё и сервер.

Главное отличие: кто видит данные

localStorage, sessionStorage и IndexedDB живут только в браузере. Сервер о них ничего не знает - данные никуда не уходят сами по себе. Если их нужно передать на бэкенд, вы делаете это вручную через fetch/XMLHttpRequest.

Cookies - единственное хранилище, связанное с сервером. Браузер автоматически прикрепляет их к каждому HTTP-запросу к этому домену в заголовке Cookie, а сервер устанавливает их через заголовок Set-Cookie. Поэтому работа с cookies (особенно для авторизации) - это обычно изменения на сервере, а не только JS-код. Более того, самые безопасные cookie (HttpOnly) вообще недоступны из JavaScript и управляются исключительно сервером.

Сравнение

localStoragesessionStorageCookiesIndexedDB
Объём~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.

Источники