Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
IndexedDB: встроенная база данных браузера
IndexedDB — это встроенный в браузер API для хранения больших объёмов структурированных данных на стороне клиента. Это мощный инструмент для создания оффлайн-приложений и кэширования данных.
Что такое IndexedDB
IndexedDB — это:
- NoSQL база данных — работает с объектами, не с таблицами
- Асинхронная — все операции асинхронные (не блокируют UI)
- Встроенная в браузер — доступна без подключения к интернету
- Объёмная — может хранить от сотен МБ до нескольких ГБ
Сравнение с другими хранилищами браузера
| Хранилище | Объём | Асинхронное | Типы данных | Использование |
|---|---|---|---|---|
| localStorage | 5-10 МБ | Нет | Только строки | Простые настройки |
| sessionStorage | 5-10 МБ | Нет | Только строки | Данные сессии |
| Cookies | 4-8 КБ | Нет | Только строки | Аутентификация |
| IndexedDB | 100 МБ+ | Да | Объекты, файлы | Большие данные |
| WebSQL | 5-50 МБ | Да | SQL-таблицы | Устаревший (не используй) |
Основные концепции IndexedDB
1. Database (База данных)
const dbRequest = indexedDB.open('myApp', 1); // Версия 1
2. Object Store (Хранилище объектов)
Аналог таблицы в обычной БД, но хранит объекты JavaScript.
3. Index (Индекс)
Оптимизирует поиск по определённым полям объектов.
4. Transaction (Транзакция)
Гарантирует целостность данных при множественных операциях.
Практический пример
Создание и инициализация
let db;
const request = indexedDB.open('UserDatabase', 1);
// Обработка ошибки
request.onerror = () => {
console.error('Ошибка открытия БД:', request.error);
};
// Успех
request.onsuccess = () => {
db = request.result;
console.log('База данных открыта');
};
// Создание/обновление структуры (версия БД изменилась)
request.onupgradeneeded = (event) => {
db = event.target.result;
// Создаём хранилище объектов
if (!db.objectStoreNames.contains('users')) {
const store = db.createObjectStore('users', { keyPath: 'id' });
// Создаём индекс по email
store.createIndex('emailIndex', 'email', { unique: true });
// Создаём индекс по имени (может быть несколько объектов с одним именем)
store.createIndex('nameIndex', 'name', { unique: false });
}
};
Добавление данных
function addUser(user) {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
const request = store.add(user);
request.onsuccess = () => {
console.log('Пользователь добавлен:', user.id);
};
request.onerror = () => {
console.error('Ошибка добавления:', request.error);
};
}
// Использование
addUser({ id: 1, name: 'Алиса', email: 'alice@example.com', age: 30 });
addUser({ id: 2, name: 'Боб', email: 'bob@example.com', age: 25 });
Получение данных
// Получить по ключу
function getUser(id) {
const transaction = db.transaction(['users'], 'readonly');
const store = transaction.objectStore('users');
const request = store.get(id);
request.onsuccess = () => {
console.log('Найденный пользователь:', request.result);
};
}
// Получить все объекты
function getAllUsers() {
const transaction = db.transaction(['users'], 'readonly');
const store = transaction.objectStore('users');
const request = store.getAll();
request.onsuccess = () => {
console.log('Все пользователи:', request.result);
};
}
// Поиск по индексу
function getUserByEmail(email) {
const transaction = db.transaction(['users'], 'readonly');
const store = transaction.objectStore('users');
const index = store.index('emailIndex');
const request = index.get(email);
request.onsuccess = () => {
console.log('Пользователь по email:', request.result);
};
}
Обновление данных
function updateUser(id, updates) {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
const request = store.get(id);
request.onsuccess = () => {
const user = request.result;
const updatedUser = { ...user, ...updates };
store.put(updatedUser); // put перезаписывает, а add вызывает ошибку
};
}
Удаление данных
function deleteUser(id) {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
const request = store.delete(id);
request.onsuccess = () => {
console.log('Пользователь удалён');
};
}
// Удалить всё
function clearAllUsers() {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
store.clear();
}
Работа с Promises (IDBPromise)
Хотя IndexedDB асинхронен, он использует callback-стиль (события), а не Promises. Но можно обернуть в Promise:
function getUser(id) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['users'], 'readonly');
const store = transaction.objectStore('users');
const request = store.get(id);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// Использование
const user = await getUser(1);
console.log(user);
Практические примеры использования
1. Кэширование API ответов
async function fetchWithCache(url) {
// Проверяем кэш
const cached = await getFromCache(url);
if (cached) {
return cached;
}
// Если нет, получаем с сервера
const response = await fetch(url);
const data = await response.json();
// Сохраняем в кэш
await saveToCache(url, data);
return data;
}
2. Оффлайн-приложение
// Сохраняем заметки оффлайн
function saveNote(note) {
const transaction = db.transaction(['notes'], 'readwrite');
const store = transaction.objectStore('notes');
store.add({ ...note, id: Date.now(), synced: false });
}
// При восстановлении интернета синхронизируем
async function syncNotes() {
const notes = await getAllNotes();
const unsyncedNotes = notes.filter(n => !n.synced);
for (const note of unsyncedNotes) {
await fetch('/api/notes', {
method: 'POST',
body: JSON.stringify(note)
});
// Обновляем статус
note.synced = true;
store.put(note);
}
}
3. Хранение больших файлов
function storeFile(file) {
const transaction = db.transaction(['files'], 'readwrite');
const store = transaction.objectStore('files');
store.add({
name: file.name,
type: file.type,
size: file.size,
data: file, // Может хранить Blob/File
uploadedAt: new Date()
});
}
Плюсы и минусы
Плюсы
- Огромный объём хранения (сотни МБ)
- Асинхронный API (не блокирует UI)
- Поддержка сложных структур данных
- Индексы для быстрого поиска
- Транзакции для целостности данных
- Доступна оффлайн
Минусы
- Callback-стиль (неудобен в использовании)
- Сложная API (много кода)
- Слабая поддержка браузерами (IE 10, старые браузеры)
- Хранение на клиенте (приватность данных)
- Ограничение по хранилищу браузера
Библиотеки для упрощения работы
// Использование Dexie.js - обёртка над IndexedDB
import Dexie from 'dexie';
const db = new Dexie('MyDatabase');
db.version(1).stores({
users: '++id, email'
});
// Теперь можно использовать Promise-стиль
await db.users.add({ name: 'Алиса', email: 'alice@example.com' });
const user = await db.users.get(1);
const allUsers = await db.users.toArray();
Ключевые выводы
- IndexedDB — мощное хранилище для больших данных на клиенте
- Используй для кэширования API, оффлайн-приложений, больших объёмов данных
- Асинхронный API требует работы с Promises или callbacks
- Рассмотри использование библиотек типа Dexie для упрощения
- Не забывай о приватности — пользователь может очистить данные