IndexedDB
IndexedDB — это встроенный в браузер механизм для хранения значительных объёмов структурированных данных на стороне клиента. Относится к классу NoSQL-баз данных, работающих в парадигме «ключ — значение». Предоставляет асинхронный интерфейс для создания, чтения, обновления и удаления записей (CRUD), поддерживает индексацию, транзакции и поиск по диапазонам. В отличие от более простого хранилища localStorage, IndexedDB не ограничен жёстким лимитом в 5–10 мегабайт (ёмкость зависит от браузера и свободного места на диске) и позволяет хранить не только строки, но и сложные объекты JavaScript, файлы, Blob-объекты и двоичные массивы.
История и стандартизация
Разработка IndexedDB была инициирована компанией Oracle и началась в 2008 году. Первоначальная спецификация была предложена как альтернатива Web SQL Database, который основывался на SQLite, но был признан неперспективным из-за проблем с совместимостью и стандартизацией. Работа над спецификацией велась в рамках Консорциума Всемирной паутины (W3C).
Первая черновая версия стандарта была опубликована в 2010 году. Ключевые изменения и доработки происходили в течение нескольких лет. В 2015 году спецификация IndexedDB была рекомендована W3C как полноценный веб-стандарт. Позднее вышла вторая версия (Indexed Database API 2.0), которая добавила поддержку двоичных ключей, улучшила работу с индексами и внесла другие уточнения.
Поддержка IndexedDB реализована во всех современных браузерах, включая Google Chrome, Mozilla Firefox, Apple Safari, Microsoft Edge и Opera. Для старых версий Internet Explorer (начиная с IE 10) также существовала частичная поддержка.
Архитектура и ключевые понятия
База данных и хранилища объектов
IndexedDB оперирует понятием базы данных (database). В рамках одного источника (origin) — комбинации протокола, домена и порта — может существовать несколько баз данных с разными именами. Каждая база данных содержит одно или несколько хранилищ объектов (object stores). Хранилище объектов — аналог таблицы в реляционных базах данных, но без фиксированной схемы: каждая запись (объект) может иметь произвольный набор полей.
Ключи и индексы
Каждая запись в хранилище объектов идентифицируется уникальным ключом. Ключ может быть:
- числом;
- строкой;
- датой;
- массивом (до определённой глубины вложенности);
- двоичным объектом (в версии 2.0).
Ключ может задаваться автоматически (с помощью генератора — счётчика) или извлекаться из самого объекта (keyPath). Для ускорения поиска по полям, отличным от ключа, создаются индексы. Индекс — это структура, которая хранит отсортированные копии значений указанного поля и ссылки на соответствующие записи.
Транзакции
Все операции чтения и записи в IndexedDB выполняются в контексте транзакций. Транзакция — это атомарная последовательность операций. Если хотя бы одна операция в транзакции завершается ошибкой, вся транзакция откатывается. Транзакции бывают трёх типов:
readonly— только чтение данных;readwrite— чтение и запись;versionchange— изменение структуры базы данных (создание или удаление хранилищ объектов и индексов).
Транзакции автоматически фиксируются (commit) после выполнения всех запланированных операций, если не было явного вызова прерывания.
Асинхронный интерфейс и события
IndexedDB использует асинхронную модель, основанную на событиях. Запросы к базе данных возвращают объекты IDBRequest, которые генерируют события success (успешное выполнение) или error (ошибка). Обработчики этих событий позволяют получить результат операции. Современный код часто использует обёртки на основе Promise или async/await, чтобы избежать «ада колбэков».
Основные операции
Открытие базы данных
Открытие базы данных осуществляется с помощью метода indexedDB.open(name, version). Если база данных с указанным именем не существует, она создаётся. Параметр version определяет версию схемы базы данных. При открытии базы данных можно подписаться на событие upgradeneeded, которое вызывается, когда версия базы данных увеличивается или база создаётся впервые. Внутри этого события выполняется создание или изменение хранилищ объектов и индексов.
Создание и изменение структуры
Изменение структуры базы данных (создание хранилищ, индексов, их удаление) возможно только в рамках транзакции типа versionchange, которая запускается во время события upgradeneeded. Пример создания хранилища объектов:
``javascript const request = indexedDB.open('MyDatabase', 1); request.onupgradeneeded = (event) => { const db = event.target.result; const store = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true }); store.createIndex('nameIndex', 'name', { unique: false }); }; ``
Добавление, чтение, обновление и удаление данных
После открытия базы данных и получения объекта IDBDatabase можно выполнять операции с данными. Все они требуют создания транзакции:
```javascript const transaction = db.transaction('users', 'readwrite'); const store = transaction.objectStore('users');
// Добавление store.add({ name: 'Иван', age: 30 });
// Чтение по ключу const getRequest = store.get(1); getRequest.onsuccess = (event) => { / event.target.result / };
// Обновление store.put({ id: 1, name: 'Пётр', age: 35 });
// Удаление store.delete(1); ```
Поиск по индексу и курсоры
Для поиска записей по полю, для которого создан индекс, используется метод index.openCursor() или index.get(). Курсор позволяет последовательно перебирать записи, удовлетворяющие условию (например, диапазону значений). Диапазоны задаются с помощью объекта IDBKeyRange:
``javascript const range = IDBKeyRange.bound('А', 'М'); // имена от А до М const index = store.index('nameIndex'); const cursorRequest = index.openCursor(range); cursorRequest.onsuccess = (event) => { const cursor = event.target.result; if (cursor) { console.log(cursor.value); cursor.continue(); } }; ``
Особенности и ограничения
Пространство имён и изоляция
Каждый веб-сайт (источник) имеет собственное изолированное пространство для IndexedDB. Данные одного сайта недоступны другому. Это обеспечивает безопасность и конфиденциальность.
Лимиты на размер
В отличие от localStorage, IndexedDB не имеет фиксированного небольшого лимита. Однако браузеры устанавливают квоты, которые могут варьироваться. Обычно браузер запрашивает у пользователя разрешение на использование более 50–100 МБ. Для больших объёмов (несколько гигабайт) также может потребоваться подтверждение. В мобильных браузерах лимиты, как правило, более строгие.
Очистка данных
Браузеры могут удалять данные IndexedDB в случае нехватки места на диске, а также при очистке истории или кэша пользователем. Разработчик не может гарантировать постоянное сохранение данных без использования дополнительных API (например, StorageManager с запросом на постоянное хранилище).
Асинхронность и сложность
API IndexedDB является асинхронным и событийно-ориентированным, что делает его более сложным в использовании по сравнению с синхронным localStorage. Для упрощения работы существуют библиотеки-обёртки, такие как Dexie.js, IDBWrapper и другие.
Применение
IndexedDB используется в веб-приложениях, которым требуется хранение значительных объёмов данных на стороне клиента без постоянного обращения к серверу. Типичные сценарии:
- Офлайн-приложения (Progressive Web Apps, PWA): кэширование данных для работы без интернета. Например, текстовые редакторы, планировщики задач, карты.
- Сложные веб-приложения: хранение настроек, пользовательских данных, истории операций. Например, почтовые клиенты (Gmail), CRM-системы, редакторы изображений.
- Игры: сохранение состояния игры, прогресса, инвентаря.
- Аналитика и логирование: временное хранение событий для последующей отправки на сервер.
- Медиа-приложения: кэширование аудио- и видеофайлов, изображений.
Безопасность
IndexedDB подчиняется политике одинакового происхождения (Same-Origin Policy). Данные, записанные одним источником, не могут быть прочитаны другим. Однако следует учитывать, что данные IndexedDB хранятся в незашифрованном виде в файловой системе браузера. При компрометации устройства злоумышленник может получить доступ к этим данным. Для хранения чувствительной информации (пароли, токены) рекомендуется использовать специализированные API, такие как Credential Management или Web Authentication, а также шифрование данных перед сохранением.
Критика и альтернативы
Основные недостатки IndexedDB — сложность API и неинтуитивная работа с транзакциями. Кроме того, производительность при большом количестве мелких операций может быть ниже, чем у специализированных решений. Альтернативами IndexedDB являются:
- localStorage — для хранения небольших объёмов простых строковых данных (до 5–10 МБ).
- Cache API — для кэширования ответов сети (используется в Service Workers).
- Web SQL Database — устаревшая технология, не поддерживаемая в современных браузерах.
- Библиотеки-обёртки — упрощают работу с IndexedDB, но не являются самостоятельными хранилищами.
Источники
- W3C Recommendation: Indexed Database API 2.0
- MDN Web Docs: IndexedDB API
- Спецификация WHATWG: Storage
- Статья «IndexedDB: The Basics» на Smashing Magazine
- Документация библиотеки Dexie.js
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →