Метод createInstance: создание нового экземпляра

Назначение метода createInstance

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

Ключевая идея — мультихранилищность внутри одного приложения:

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

Базовый синтаксис

const store = localForage.createInstance(options);

options — объект конфигурации, аналогичный глобальной настройке, но применяемый только к конкретному экземпляру.


Основные параметры конфигурации

Экземпляр может быть настроен независимо от глобального состояния:

const userStore = localForage.createInstance({
  name: 'appDB',
  storeName: 'users',
  driver: localForage.INDEXEDDB
});

Разбор параметров:

  • name — имя базы данных (логическое разделение на уровне storage engine)

  • storeName — имя object store (особенно важно для IndexedDB)

  • driver — приоритет или конкретный драйвер хранения:

    • IndexedDB
    • WebSQL
    • localStorage

Изоляция экземпляров

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

const a = localForage.createInstance({
  name: 'db',
  storeName: 'moduleA'
});

const b = localForage.createInstance({
  name: 'db',
  storeName: 'moduleB'
});

await a.setItem('key', 'A');
await b.setItem('key', 'B');

Несмотря на одинаковую базу db, данные не пересекаются из-за разных storeName.


Отличие от глобальной конфигурации

Глобальная настройка:

localForage.config({
  name: 'appDB',
  storeName: 'default'
});

Ограничения:

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

Экземпляры через createInstance:

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

Поведение драйверов в экземплярах

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

const idbStore = localForage.createInstance({
  name: 'db',
  storeName: 'fast',
  driver: localForage.INDEXEDDB
});

const lsStore = localForage.createInstance({
  name: 'db',
  storeName: 'fallback',
  driver: localForage.LOCALSTORAGE
});

Логика применения:

  • IndexedDB — основной быстрый слой
  • localStorage — резервный вариант
  • WebSQL — устаревший, используется только при необходимости совместимости

Переиспользование экземпляров

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

const cacheStore = localForage.createInstance({
  name: 'cacheDB',
  storeName: 'responses'
});

async function saveResponse(key, data) {
  return cacheStore.setItem(key, data);
}

Преимущества:

  • уменьшение накладных расходов на конфигурацию
  • централизованная работа с конкретным хранилищем
  • упрощение архитектуры приложения

Асинхронная инициализация экземпляра

Хотя createInstance сам по себе синхронный, драйвер внутри может инициализироваться асинхронно.

Типичный паттерн:

const store = localForage.createInstance({
  name: 'db',
  storeName: 'initTest'
});

await store.ready();

Метод ready() гарантирует, что выбранный драйвер полностью инициализирован.


Поведение ключей внутри экземпляра

Ключи всегда локальны для конкретного экземпляра:

const users = localForage.createInstance({
  name: 'db',
  storeName: 'users'
});

const settings = localForage.createInstance({
  name: 'db',
  storeName: 'settings'
});

await users.setItem('theme', 'dark');
await settings.setItem('theme', 'light');

Несмотря на одинаковый ключ theme, значения не конфликтуют.


Использование нескольких экземпляров в архитектуре приложения

Типовая сегментация:

const authStore = localForage.createInstance({
  name: 'app',
  storeName: 'auth'
});

const profileStore = localForage.createInstance({
  name: 'app',
  storeName: 'profile'
});

const cacheStore = localForage.createInstance({
  name: 'app',
  storeName: 'cache'
});

Логика:

  • auth — токены и сессии
  • profile — данные пользователя
  • cache — временные данные

Клонирование конфигураций

Возможен шаблонный подход:

const baseConfig = {
  name: 'appDB',
  driver: localForage.INDEXEDDB
};

const productsStore = localForage.createInstance({
  ...baseConfig,
  storeName: 'products'
});

const ordersStore = localForage.createInstance({
  ...baseConfig,
  storeName: 'orders'
});

Это снижает дублирование конфигурации и упрощает поддержку.


Влияние на производительность

Использование createInstance влияет на архитектурную, но не на вычислительную сложность:

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

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


Частые ошибки при работе с createInstance

Неправильное ожидание глобальности:

const a = localForage.createInstance({ storeName: 'a' });
const b = localForage.createInstance({ storeName: 'b' });

// ожидание общего пространства данных — ошибка архитектуры

Создание экземпляров в циклах:

for (let i = 0; i < 100; i++) {
  localForage.createInstance({ storeName: 'store' + i });
}

Это приводит к:

  • лишним объектам
  • дублированию инициализации драйверов
  • ухудшению производительности

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

Все методы экземпляра остаются асинхронными:

const store = localForage.createInstance({
  name: 'app',
  storeName: 'data'
});

store.setItem('id', 123)
  .then(() => store.getItem('id'))
  .then(value => {
    console.log(value);
  });

или через async/await:

const value = await store.getItem('id');

Поведение при смене драйвера

Экземпляр фиксирует драйвер при инициализации:

const store = localForage.createInstance({
  driver: localForage.LOCALSTORAGE
});

Если драйвер недоступен:

  • происходит fallback (если указан массив драйверов)
  • либо выбрасывается ошибка инициализации

Множественные экземпляры и масштабирование

В крупных приложениях используется стратегия:

  • один экземпляр = одна бизнес-сущность
  • минимизация пересечений ключей
  • разделение по слоям данных

Пример слоистой архитектуры:

  • persistence layer (основные данные)
  • cache layer (временные данные)
  • sync layer (данные для синхронизации)

Каждый слой — отдельный createInstance.