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

Что такое IndexedDB?

1.8 Middle🔥 121 комментариев
#Браузер и сетевые технологии

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

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

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

IndexedDB: встроенная база данных браузера

IndexedDB — это встроенный в браузер API для хранения больших объёмов структурированных данных на стороне клиента. Это мощный инструмент для создания оффлайн-приложений и кэширования данных.

Что такое IndexedDB

IndexedDB — это:

  • NoSQL база данных — работает с объектами, не с таблицами
  • Асинхронная — все операции асинхронные (не блокируют UI)
  • Встроенная в браузер — доступна без подключения к интернету
  • Объёмная — может хранить от сотен МБ до нескольких ГБ

Сравнение с другими хранилищами браузера

ХранилищеОбъёмАсинхронноеТипы данныхИспользование
localStorage5-10 МБНетТолько строкиПростые настройки
sessionStorage5-10 МБНетТолько строкиДанные сессии
Cookies4-8 КБНетТолько строкиАутентификация
IndexedDB100 МБ+ДаОбъекты, файлыБольшие данные
WebSQL5-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();

Ключевые выводы

  1. IndexedDB — мощное хранилище для больших данных на клиенте
  2. Используй для кэширования API, оффлайн-приложений, больших объёмов данных
  3. Асинхронный API требует работы с Promises или callbacks
  4. Рассмотри использование библиотек типа Dexie для упрощения
  5. Не забывай о приватности — пользователь может очистить данные
Что такое IndexedDB? | PrepBro