IndexedDB представляет собой низкоуровневую встроенную в браузер систему хранения структурированных данных, основанную на транзакционной модели и индексировании объектов. В контексте веб-разработки она занимает промежуточное положение между простыми ключ-значение хранилищами и полноценными встраиваемыми базами данных. Понимание её архитектуры критически важно для корректного восприятия того, как работает localForage, поскольку именно IndexedDB является одним из основных бэкендов, используемых этой библиотекой в современных браузерах.
Базовая архитектура IndexedDB строится вокруг нескольких ключевых сущностей: базы данных, объектных хранилищ, транзакций и индексов. Каждая из этих сущностей формирует слой абстракции над физическим хранением данных внутри браузера.
IndexedDB работает с именованными базами данных, каждая из которых имеет версию. Версионность — фундаментальный элемент архитектуры. Любое структурное изменение (создание или удаление object store, добавление индексов) требует увеличения версии базы.
При открытии базы происходит сравнение версии, указанной в запросе, с текущей версией хранилища. Если версии не совпадают, инициируется событие обновления структуры. Это означает, что схема данных не является статичной и эволюционирует через управляемые миграции.
Object store в IndexedDB — аналог таблицы в реляционных базах данных, но с более гибкой моделью. Он хранит JavaScript-объекты без строгой схемы. Каждый объект ассоциируется с ключом, который может быть задан явно или сгенерирован автоматически через keyPath или key generator.
Особенность архитектуры заключается в том, что данные не нормализуются и не требуют фиксированной структуры. Это позволяет хранить сложные вложенные объекты без предварительного преобразования.
Индексы создаются поверх object store и обеспечивают альтернативные пути доступа к данным. Они позволяют выполнять выборки не только по первичному ключу, но и по значениям полей объектов.
Внутренняя реализация индексов в IndexedDB основана на B-tree-подобных структурах, оптимизированных для диапазонных запросов. Это делает возможным эффективное выполнение запросов типа range scan без полного перебора хранилища.
IndexedDB строго транзакционна. Любая операция чтения или записи выполняется внутри транзакции, которая определяет:
Транзакции в IndexedDB обладают атомарностью: либо все операции внутри транзакции выполняются успешно, либо откатываются полностью. Это обеспечивает устойчивость к частичным сбоям.
Важной особенностью архитектуры является автоматическое завершение транзакций. Если в рамках транзакции не происходит активности, она закрывается браузером, что требует от разработчика аккуратного управления асинхронными операциями.
IndexedDB построена на событийной модели, а не на промисах (в базовом API). Каждая операция возвращает request-объект, который генерирует события success и error.
Эта модель отражает низкоуровневую природу API и требует явного управления состоянием операций. Асинхронность реализована через event loop браузера, что позволяет не блокировать основной поток исполнения.
localForage абстрагирует эту модель, предоставляя промисифицированный интерфейс, скрывающий request/event детали и приводящий API к более современному стилю async/await.
IndexedDB не является единственным уровнем хранения. В браузерной архитектуре присутствует несколько слоёв:
IndexedDB располагается между простыми storage API и кэшированием сетевых ресурсов, обеспечивая баланс между гибкостью и производительностью.
localForage использует IndexedDB как основной backend при его доступности, автоматически переключаясь на альтернативы при необходимости.
Архитектура localForage строится как слой унификации над несколькими механизмами хранения. Основная идея заключается в предоставлении единого API key-value хранилища, независимо от используемого backend.
В случае IndexedDB библиотека:
Таким образом IndexedDB используется не напрямую, а как низкоуровневая инфраструктура.
IndexedDB поддерживает структурированный клон (structured clone algorithm), что позволяет хранить большинство типов JavaScript-объектов без ручной сериализации. Однако в контексте localForage часто применяется дополнительный слой сериализации для обеспечения совместимости между драйверами.
Типичная архитектура хранения включает:
При чтении происходит обратное преобразование, обеспечивающее прозрачность для пользователя API.
Одним из ключевых архитектурных решений localForage является система драйверов. IndexedDB рассматривается как один из драйверов наряду с WebSQL (устаревший) и localStorage.
Алгоритм выбора драйвера основан на проверке поддержки среды:
Это обеспечивает переносимость кода между браузерами с разными уровнями поддержки технологий.
IndexedDB оптимизирована для больших объёмов данных и конкурентного доступа. Архитектура позволяет:
Однако конкурентность ограничена моделью транзакций: конфликтующие операции на один store могут блокировать друг друга.
localForage минимизирует сложность управления конкурентностью, скрывая транзакционные детали и предоставляя последовательный API.
Несмотря на мощную архитектуру, IndexedDB имеет ряд особенностей:
Эти особенности напрямую влияют на поведение библиотек верхнего уровня, включая localForage, которая вынуждена учитывать неоднородность среды.
IndexedDB интегрируется в event loop браузера через микротаски и макротаски, в зависимости от реализации движка. Операции чтения и записи не блокируют основной поток, но могут иметь задержки, зависящие от нагрузки на storage subsystem.
localForage добавляет дополнительный слой планирования операций, сглаживая асинхронное поведение и уменьшая вероятность гонок при последовательных вызовах.
В рамках архитектуры localForage IndexedDB выполняет роль основного высокопроизводительного хранилища, обеспечивающего:
Все остальные уровни библиотеки ориентированы на то, чтобы скрыть сложность этой системы и предоставить единый интерфейс работы с данными независимо от внутреннего механизма хранения.