Learning Book

Хранилища: localStorage, sessionStorage и IndexedDB

Web Storage и IndexedDB

localStorage и sessionStorage

// localStorage — хранится до явного удаления
localStorage.setItem('theme', 'dark')
localStorage.getItem('theme')     // 'dark'
localStorage.removeItem('theme')
localStorage.clear()              // очистить всё

// sessionStorage — хранится до закрытия вкладки
sessionStorage.setItem('cart', JSON.stringify(cartData))
const cart = JSON.parse(sessionStorage.getItem('cart') || '[]')

// Перебор всех ключей
for (let i = 0; i < localStorage.length; i++) {
  const key = localStorage.key(i)
  const value = localStorage.getItem(key)
  console.log(key, value)
}

// Реакция на изменения из другой вкладки
window.addEventListener('storage', (event) => {
  if (event.key === 'theme') {
    applyTheme(event.newValue)
  }
})
localStorage хранит только строки! Объекты нужно сериализовать через JSON. Максимальный размер — обычно 5-10 МБ. Не подходит для бинарных данных и больших объёмов.

Когда что использовать

localStorage:
  - Настройки пользователя (тема, язык)
  - Токены аутентификации (но лучше httpOnly cookie!)
  - Кэш небольших данных

sessionStorage:
  - Данные формы (защита от случайного закрытия)
  - Временное состояние (шаги wizard)
  - Данные одной сессии

IndexedDB:
  - Большие объёмы данных (>5МБ)
  - Бинарные данные (файлы, изображения)
  - Сложные запросы, индексы
  - Работа оффлайн (Service Worker)

IndexedDB через idb

import { openDB } from 'idb'

// Открытие базы с migration
const db = await openDB('my-app', 1, {
  upgrade(db, oldVersion, newVersion) {
    if (oldVersion < 1) {
      const store = db.createObjectStore('notes', {
        keyPath: 'id',
        autoIncrement: true
      })
      store.createIndex('by-date', 'createdAt')
    }
  }
})

// CRUD операции
// Добавить
const id = await db.add('notes', {
  title: 'Заметка',
  content: 'Текст...',
  createdAt: new Date()
})

// Получить
const note = await db.get('notes', id)

// Обновить
await db.put('notes', { ...note, content: 'Обновлённый текст' })

// Удалить
await db.delete('notes', id)

// Получить все
const allNotes = await db.getAll('notes')

// Запрос по индексу
const recentNotes = await db.getAllFromIndex(
  'notes',
  'by-date',
  IDBKeyRange.lowerBound(new Date(Date.now() - 86400000))
)
// Кэширование ресурсов (в Service Worker)
const CACHE_NAME = 'my-app-v1'

// Установка — кэшируем статику
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache =>
      cache.addAll(['/index.html', '/app.js', '/styles.css'])
    )
  )
})

// Fetch — отдаём из кэша если есть
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then(cached =>
      cached || fetch(event.request)
    )
  )
})

Cache API идеально для Progressive Web Apps (PWA) — позволяет работать оффлайн.