Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Хранилище данных на клиенте
В браузере есть несколько механизмов для хранения данных. Каждый имеет свои преимущества и ограничения. Выбор зависит от размера данных, времени жизни и требований по безопасности.
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' });
Данные теряются при обновлении страницы.
Сравнение
| Метод | Размер | Асинхронно | Между сессиями | Между вкладками | Безопасность |
|---|---|---|---|---|---|
| LocalStorage | 5-10MB | Нет | Да | Да | Низкая |
| SessionStorage | 5-10MB | Нет | Нет | Нет | Низкая |
| IndexedDB | 50MB+ | Да | Да | Да | Низкая |
| Cookies | 4KB | Нет | Да | Да | Средняя |
| Memory | Ограничено RAM | Да | Нет | Нет | Высокая |
Рекомендации
- Для простых настроек (тема, язык) -> localStorage
- Для чувствительных данных (токены) -> httpOnly cookies или IndexedDB с шифрованием
- Для больших данных (кэш запросов) -> IndexedDB
- Для временных данных в сессии -> SessionStorage или в переменных