Что такое IndexedDB и для чего он нужен?
Что такое IndexedDB
IndexedDB — низкоуровневое браузерное API для хранения структурированных данных на клиенте, включая файлы и blob-объекты. Это полноценная транзакционная объектная база данных (NoSQL), которая работает асинхронно и позволяет хранить существенно больший объём данных, чем localStorage — лимит обычно зависит от свободного места на диске, а не фиксирован жёстко.
Основные понятия
- База данных (database) — именованное хранилище с номером версии, открывается через
indexedDB.open(name, version). - Хранилище объектов (object store) — аналог таблицы в реляционной БД, хранит JS-объекты по ключу.
- Индекс (index) — позволяет искать записи не только по первичному ключу, но и по значению другого поля объекта.
- Транзакция (transaction) — все операции чтения и записи выполняются в рамках транзакции с режимом
readonlyилиreadwriteнад одним или несколькими object store. - Курсор (cursor) — механизм последовательного перебора записей хранилища.
Асинхронность и событийная модель
API построено на событиях, а не на промисах: методы add, get, put, delete возвращают объект IDBRequest, у которого нужно слушать onsuccess и onerror. Это исторически неудобно, поэтому на практике почти всегда используют обёртки — библиотеку idb или собственный Promise-wrapper.
Версионирование схемы
При открытии базы указывается номер версии. Если он больше текущей версии в браузере, срабатывает событие onupgradeneeded — единственное место, где разрешено создавать или удалять object store и индексы. Попытка изменить схему вне этого колбэка приведёт к ошибке.
Отличие от localStorage
- localStorage хранит только строки, работает синхронно и блокирует главный поток, лимит около 5-10 МБ.
- IndexedDB хранит структурированные данные (объекты, Blob, File, ArrayBuffer), работает асинхронно, лимит значительно больше, поддерживает индексы и полноценные транзакции.
Когда использовать
- Offline-first приложения и PWA — хранение данных для работы без сети.
- Кеширование в связке с Service Worker, например по стратегии cache-then-network.
- Хранение больших объёмов данных: файлов, изображений, результатов сложных запросов.
Ограничения
Doступ к базе ограничен same-origin политикой, квоты различаются между браузерами, а для гарантии, что браузер не очистит хранилище автоматически, стоит запрашивать persistent storage через navigator.storage.persist().
Что хочет услышать интервьюер
Понимание, что это асинхронная транзакционная NoSQL база данных в браузере, а не просто «localStorage побольше»
Знание ключевых сущностей: database, object store, index, transaction, cursor
Понимание событийной природы API и того, зачем нужны обёртки вроде библиотеки idb
Знание механизма версионирования и назначения onupgradeneeded
Понимание сценариев использования (offline, PWA, большие данные) и отличий от localStorage/sessionStorage
Пример: Работа с IndexedDB через нативное API
// Открываем (или создаём) базу данных версии 1
const request = indexedDB.open('shop', 1);
// Вызывается только при создании базы или повышении версии
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
// создаём хранилище объектов с ключевым полем id
const store = db.createObjectStore('products', { keyPath: 'id' });
// добавляем индекс для поиска по названию товара
store.createIndex('byName', 'name', { unique: false });
};
request.onsuccess = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
const tx = db.transaction('products', 'readwrite');
const store = tx.objectStore('products');
store.add({ id: 1, name: 'Клавиатура', price: 2500 });
tx.oncomplete = () => console.log('Транзакция завершена');
};
request.onerror = (event) => {
console.error('Ошибка открытия базы данных', (event.target as IDBOpenDBRequest).error);
};
Пример: Тот же код с промис-обёрткой idb
import { openDB } from 'idb';
async function getProducts() {
const db = await openDB('shop', 1, {
upgrade(db) {
const store = db.createObjectStore('products', { keyPath: 'id' });
store.createIndex('byName', 'name');
},
});
// читаем все записи из хранилища одним асинхронным вызовом
return db.getAll('products');
}
Типичные ошибки
Путают IndexedDB с localStorage, называя её просто key-value хранилищем для строк
Считают API синхронным и пытаются использовать await напрямую без промис-обёртки
Забывают, что менять схему (создавать object store, индексы) можно только внутри onupgradeneeded
Не знают, что транзакция автоматически завершается, как только не остаётся активных запросов
Не упоминают ограничения: same-origin политику, различия квот между браузерами и возможность автоматической очистки данных


