Изоляция данных между экземплярами

Библиотека localForage построена вокруг идеи унифицированного асинхронного хранилища, которое скрывает различия между IndexedDB, WebSQL и localStorage. Одним из ключевых механизмов её архитектуры является поддержка нескольких независимых экземпляров, каждый из которых может иметь собственную конфигурацию и полностью изолированное пространство данных.

Изоляция в данном контексте означает невозможность пересечения ключей, настроек драйверов и внутреннего состояния между разными экземплярами, даже если они используются в одном и том же приложении и в рамках одного домена.


Базовый экземпляр и глобальная конфигурация

При подключении localForage создаётся дефолтный экземпляр, использующий глобальную конфигурацию:

  • name — имя базы данных (для IndexedDB)
  • storeName — имя хранилища
  • driver — приоритет используемых драйверов

Этот экземпляр является общим состоянием библиотеки и используется, если явно не создаются дополнительные экземпляры.

Ключевая особенность заключается в том, что изменение конфигурации через config() влияет только на текущий глобальный экземпляр и не затрагивает уже созданные изолированные экземпляры.


Создание изолированных экземпляров через createInstance

Механизм полной изоляции реализуется через метод createInstance().

Каждый вызов формирует независимый объект со своей конфигурацией:

  • собственное пространство ключей
  • собственный набор настроек
  • независимый драйверный контекст

При использовании IndexedDB изоляция достигается через создание отдельной базы данных или отдельного object store внутри одной базы, в зависимости от параметров конфигурации.

Пример логики изоляции:

  • экземпляр A использует storeName: "cache"
  • экземпляр B использует storeName: "session"

Несмотря на использование одного и того же драйвера, данные физически разделены.


Механизмы изоляции на уровне драйверов

IndexedDB

В IndexedDB изоляция достигается через комбинацию:

  • имени базы данных (name)
  • имени object store (storeName)

Каждый экземпляр формирует собственную логическую область хранения. Даже при совпадении ключей данные не пересекаются, так как принадлежат разным store.

Важно учитывать, что IndexedDB не допускает динамического изменения структуры object store без миграции версии базы, поэтому localForage управляет этим через внутренние версии и пересоздание соединений.


WebSQL

В WebSQL изоляция реализуется через:

  • имя базы данных
  • таблицу хранения

Каждый экземпляр использует собственную таблицу или логическую сегментацию таблиц, что предотвращает коллизии ключей.


localStorage

В localStorage отсутствует полноценная многобазовая модель, поэтому изоляция достигается через:

  • префиксацию ключей
  • комбинацию name + storeName + key

Каждый экземпляр формирует уникальный namespace, который добавляется к каждому ключу при записи и чтении данных.

Таким образом, даже при одинаковом ключе "user", данные будут различаться:

  • экземпляр A → appA_user
  • экземпляр B → appB_user

Пространство ключей и предотвращение коллизий

Одним из ключевых аспектов изоляции является формирование уникального пространства ключей.

localForage использует внутренний механизм нормализации ключей, который включает:

  • имя приложения (name)
  • имя хранилища (storeName)
  • внутренний префикс драйвера

В результате формируется составной идентификатор, исключающий пересечение данных между экземплярами.

Это особенно важно при использовании микрофронтендов, где несколько независимых приложений работают в одном origin.


Независимость конфигурации драйверов

Каждый экземпляр может иметь собственный приоритет драйверов:

  • IndexedDB
  • WebSQL
  • localStorage

Изоляция проявляется не только в данных, но и в выборе механизма хранения. Один экземпляр может работать исключительно через IndexedDB, тогда как другой — использовать localStorage как fallback.

Это приводит к различным характеристикам:

  • различная производительность
  • различный объём хранимых данных
  • различная устойчивость к очистке браузером

Внутреннее состояние экземпляра

Каждый экземпляр localForage поддерживает собственное состояние:

  • кеш открытых соединений
  • инициализированный драйвер
  • очередь операций до готовности хранилища

Это означает, что операции одного экземпляра не блокируют и не влияют на другой, даже если физически они используют один и тот же backend.

При этом инициализация (ready()) выполняется отдельно для каждого экземпляра, что исключает гонки состояний.


Практические сценарии изоляции

Разделение кэша и пользовательских данных

Один экземпляр используется для временного кэша:

  • изображения
  • API-ответы
  • промежуточные вычисления

Другой — для постоянных пользовательских данных:

  • настройки
  • профили
  • состояние приложения

Такое разделение позволяет безопасно очищать кэш без риска потери критических данных.


Изоляция модулей в одном приложении

В модульных системах каждый модуль может иметь собственный экземпляр:

  • модуль аналитики
  • модуль авторизации
  • модуль оффлайн-режима

Каждый из них работает в своём namespace, не пересекаясь по ключам и структурам данных.


Микрофронтенды

При работе нескольких независимых фронтенд-приложений в одном домене изоляция предотвращает:

  • перезапись ключей
  • конфликт версий данных
  • непредсказуемое поведение при очистке storage

Каждое приложение использует собственный createInstance() с уникальным name.


Потенциальные проблемы при неправильной изоляции

Несмотря на встроенные механизмы, ошибки конфигурации могут приводить к пересечению данных:

  • одинаковый name и storeName у разных экземпляров
  • отсутствие префиксов в localStorage-режиме
  • ручное использование одинаковых ключей вне localForage API

Особенно критичным является сценарий, когда несколько экземпляров используют один и тот же namespace, но ожидают независимого состояния.


Ограничения изоляции

Изоляция в localForage не является физической виртуализацией хранилища. Все экземпляры всё равно работают в рамках одного origin и подчиняются ограничениям браузера:

  • общий лимит дискового пространства
  • общие политики очистки данных
  • единые ограничения безопасности IndexedDB

Поэтому изоляция гарантирует логическое разделение, но не физическое выделение ресурсов.


Поведение при смене конфигурации

После создания экземпляра изменение конфигурации через config() не влияет на уже существующие экземпляры. Это обеспечивает стабильность поведения, но требует внимательного проектирования:

  • конфигурация фиксируется на момент создания
  • повторная инициализация требует создания нового экземпляра
  • пересечение старых и новых настроек не происходит

Итоговая модель изоляции

Изоляция данных между экземплярами формируется за счёт нескольких уровней:

  • логический уровень (namespace и ключи)
  • драйверный уровень (IndexedDB / WebSQL / localStorage)
  • уровень экземпляра (состояние и очереди операций)

Комбинация этих уровней обеспечивает независимое поведение каждого createInstance(), предотвращая пересечение данных и позволяя строить модульные системы хранения внутри одного приложения.