← Назад к вопросам

Как хранить данные на клиенте?

2.0 Middle🔥 202 комментариев
#JavaScript Core

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Хранилище данных на клиенте

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

LocalStorage

Простое синхронное хранилище. Данные сохраняются между сессиями браузера.

// Сохранить
localStorage.setItem('theme', 'dark');
localStorage.setItem('user', JSON.stringify({ id: 1, name: 'John' }));

// Получить
const theme = localStorage.getItem('theme');  // 'dark'
const user = JSON.parse(localStorage.getItem('user'));  // { id: 1, name: 'John' }

// Удалить
localStorage.removeItem('theme');

// Очистить всё
localStorage.clear();

// Получить все ключи
for (let i = 0; i < localStorage.length; i++) {
  const key = localStorage.key(i);
  console.log(key, localStorage.getItem(key));
}

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

  • Максимум 5-10 МБ на домен
  • Синхронное (блокирует UI при больших объемах)
  • Не шифруется (не хранить секреты)
  • Доступно из всех вкладок одного домена

SessionStorage

Аналогичен localStorage, но очищается при закрытии вкладки.

sessionStorage.setItem('formData', JSON.stringify({ field1: 'value1' }));
const formData = JSON.parse(sessionStorage.getItem('formData'));

// Очищается автоматически при закрытии вкладки

Используй для временных данных в текущей сессии.

IndexedDB

Мощное асинхронное хранилище больших объемов данных. Поддерживает индексы и транзакции.

const dbRequest = indexedDB.open('myApp', 1);

dbRequest.onupgradeneeded = (event) => {
  const db = event.target.result;
  
  // Создать объектные хранилища (таблицы)
  if (!db.objectStoreNames.contains('users')) {
    const store = db.createObjectStore('users', { keyPath: 'id' });
    store.createIndex('email', 'email', { unique: true });
  }
};

dbRequest.onsuccess = (event) => {
  const db = event.target.result;
  
  // Добавить данные
  const transaction = db.transaction('users', 'readwrite');
  const store = transaction.objectStore('users');
  store.add({ id: 1, name: 'John', email: 'john@example.com' });
  
  // Получить данные
  const getRequest = store.get(1);
  getRequest.onsuccess = () => {
    console.log(getRequest.result);  // { id: 1, name: 'John', ... }
  };
  
  // Поиск по индексу
  const emailIndex = store.index('email');
  const emailRequest = emailIndex.get('john@example.com');
  emailRequest.onsuccess = () => {
    console.log(emailRequest.result);
  };
  
  // Получить все
  const allRequest = store.getAll();
  allRequest.onsuccess = () => {
    console.log(allRequest.result);  // Массив всех пользователей
  };
};

Promise-обертка для IndexedDB

IndexedDB имеет громоздкий API. Обычно используют либрей или обертку:

class DB {
  constructor(name, version) {
    this.name = name;
    this.version = version;
    this.db = null;
  }

  async open() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.name, this.version);
      
      request.onupgradeneeded = (e) => {
        const db = e.target.result;
        if (!db.objectStoreNames.contains('items')) {
          db.createObjectStore('items', { keyPath: 'id' });
        }
      };
      
      request.onsuccess = () => {
        this.db = request.result;
        resolve(this.db);
      };
      
      request.onerror = () => reject(request.error);
    });
  }

  async add(storeName, data) {
    const tx = this.db.transaction(storeName, 'readwrite');
    return new Promise((resolve, reject) => {
      const request = tx.objectStore(storeName).add(data);
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  async get(storeName, key) {
    const tx = this.db.transaction(storeName, 'readonly');
    return new Promise((resolve, reject) => {
      const request = tx.objectStore(storeName).get(key);
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  async getAll(storeName) {
    const tx = this.db.transaction(storeName, 'readonly');
    return new Promise((resolve, reject) => {
      const request = tx.objectStore(storeName).getAll();
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }
}

// Использование
const db = new DB('myApp', 1);
await db.open();
await db.add('items', { id: 1, title: 'Task 1' });
const item = await db.get('items', 1);
const allItems = await db.getAll('items');

Cookies

Ксожалению, браузер автоматически отправляет cookies на сервер в каждом запросе. Используй только для данных, которые нужны на сервере.

// Установить cookie
document.cookie = 'theme=dark; path=/; max-age=86400';  // 1 день
document.cookie = 'token=abc123; path=/; secure; httponly';  // secure и httponly на сервере

// Получить все cookies
const cookies = document.cookie.split(';').map(c => c.trim());

// Helper функция
function getCookie(name) {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop().split(';').shift();
}

const theme = getCookie('theme');

Memory (в переменных)

Для данных, которые нужны только в текущей сессии браузера:

class AppState {
  constructor() {
    this.cache = new Map();
  }

  set(key, value) {
    this.cache.set(key, value);
  }

  get(key) {
    return this.cache.get(key);
  }

  clear() {
    this.cache.clear();
  }
}

const appState = new AppState();
appState.set('currentUser', { id: 1, name: 'John' });

Данные теряются при обновлении страницы.

Сравнение

МетодРазмерАсинхронноМежду сессиямиМежду вкладкамиБезопасность
LocalStorage5-10MBНетДаДаНизкая
SessionStorage5-10MBНетНетНетНизкая
IndexedDB50MB+ДаДаДаНизкая
Cookies4KBНетДаДаСредняя
MemoryОграничено RAMДаНетНетВысокая

Рекомендации

  • Для простых настроек (тема, язык) -> localStorage
  • Для чувствительных данных (токены) -> httpOnly cookies или IndexedDB с шифрованием
  • Для больших данных (кэш запросов) -> IndexedDB
  • Для временных данных в сессии -> SessionStorage или в переменных
Как хранить данные на клиенте? | PrepBro