Полная сигнатура defineDriver

Метод defineDriver служит механизмом расширения системы хранения, позволяя подключать собственные драйверы, совместимые с внутренним контрактом библиотеки. Через него формируется слой абстракции над различными механизмами хранения данных (IndexedDB, WebSQL, localStorage), а также реализуются пользовательские адаптеры с произвольной логикой.


Базовая сигнатура

defineDriver(driverObject: Object, callback?: Function): Promise<void>

Метод возвращает Promise, который резолвится после успешной регистрации драйвера. Второй аргумент — необязательный callback, используемый в старом стиле асинхронного API.


Поведение метода

defineDriver выполняет регистрацию объекта-драйвера в глобальном реестре доступных хранилищ. После регистрации драйвер становится доступным для использования через setDriver.

Внутренне происходит:

  • проверка структуры объекта драйвера;
  • привязка обязательных методов;
  • добавление драйвера в список доступных стратегий хранения;
  • инициализация метаданных поддержки окружения (если определено _support или supports).

Структура объекта драйвера

Объект, передаваемый в defineDriver, должен соответствовать контракту драйвера. Он описывает набор обязательных и дополнительных методов, обеспечивающих CRUD-операции и управление состоянием хранилища.

Обязательные поля

_driver

Уникальный строковый идентификатор драйвера.

_driver: 'customDriverName'

Используется системой для регистрации и выбора драйвера.


_initStorage

Метод инициализации хранилища. Вызывается при активации драйвера через setDriver.

_initStorage(options): Promise<void>

Задачи:

  • подготовка внутреннего состояния;
  • открытие соединений (IndexedDB, file storage и т.п.);
  • настройка схемы хранения.

getItem
getItem(key): Promise<any>

Возвращает значение по ключу. При отсутствии данных возвращается null.


setItem
setItem(key, value): Promise<any>

Сохраняет значение по ключу и возвращает сохранённое значение.


removeItem
removeItem(key): Promise<void>

Удаляет запись по ключу.


clear
clear(): Promise<void>

Полная очистка хранилища драйвера.


length
length(): Promise<number>

Возвращает количество записей в хранилище.


key
key(index): Promise<string | null>

Возвращает ключ по индексу.


iterate
iterate(iteratorFunction, callback?): Promise<any>

Итерация по всем ключам и значениям хранилища.


Полная сигнатура с типизацией

В терминах расширенного описания интерфейса:

interface Driver {
  _driver: string;
  _initStorage: (options?: any) => Promise<void>;

  getItem: (key: string) => Promise<any>;
  setItem: (key: string, value: any) => Promise<any>;
  removeItem: (key: string) => Promise<void>;
  clear: () => Promise<void>;

  length: () => Promise<number>;
  key: (index: number) => Promise<string | null>;

  iterate: (
    iterator: (value: any, key: string, iterationNumber: number) => any,
    callback?: Function
  ) => Promise<any>;

  _support?: boolean | (() => boolean);
}

Полная сигнатура defineDriver

Фактическое определение метода:

defineDriver(
  driver: Driver,
  callback?: (error?: Error) => void
): Promise<void>

Внутренние этапы регистрации

После вызова defineDriver выполняется последовательность шагов:

1. Валидация объекта драйвера

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

2. Нормализация интерфейса

Методы драйвера оборачиваются в промисы, если возвращают значения в синхронном виде. Это обеспечивает единый асинхронный контракт.

3. Регистрация в реестре

Драйвер добавляется в внутренний массив доступных стратегий хранения.

4. Обработка callback

Если передан callback, он вызывается после завершения регистрации:

callback(error)

При успешной регистрации error равен undefined.

5. Резолв Promise

Основной результат метода возвращается через Promise.resolve() после завершения всех шагов.


Особенности реализации драйверов

Асинхронная модель

Все операции приводятся к асинхронной форме, даже если исходный механизм хранения синхронный (например, localStorage). Это обеспечивает единообразное API.


Контекст хранения

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


Совместимость с setDriver

После регистрации драйвера через defineDriver он становится доступным для выбора:

setDriver('customDriverName')

Поведение при ошибках

Ошибки регистрации обрабатываются следующим образом:

  • отсутствие _driver приводит к немедленному отклонению Promise;
  • отсутствие обязательных методов вызывает ошибку валидации;
  • ошибки инициализации _initStorage прерывают процесс активации.

Расширенные возможности _support

Поле _support позволяет определить доступность драйвера в текущей среде.

Возможные формы:

_support: true

или

_support: () => {
  return typeof indexedDB !== 'undefined';
}

Если функция возвращает false, драйвер исключается из выбора при автоматическом определении.


Пример структуры драйвера

const customDriver = {
  _driver: 'custom-driver',

  _initStorage: async function () {
    this._db = new Map();
  },

  getItem: async function (key) {
    return this._db.get(key) || null;
  },

  setItem: async function (key, value) {
    this._db.set(key, value);
    return value;
  },

  removeItem: async function (key) {
    this._db.delete(key);
  },

  clear: async function () {
    this._db.clear();
  },

  length: async function () {
    return this._db.size;
  },

  key: async function (index) {
    return Array.from(this._db.keys())[index] || null;
  },

  iterate: async function (fn) {
    let i = 0;
    for (const [key, value] of this._db.entries()) {
      fn(value, key, i++);
    }
  }
};

Регистрация драйвера через defineDriver

defineDriver(customDriver)
  .then(() => console.log('registered'));

или

defineDriver(customDriver, (err) => {
  if (err) {
    console.error(err);
  }
});

Взаимодействие с внутренним реестром

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


Контракт совместимости

Любой драйвер, зарегистрированный через defineDriver, обязан сохранять следующие свойства:

  • асинхронность всех операций;
  • предсказуемое поведение CRUD-методов;
  • стабильность ключей и индексов;
  • отсутствие побочных эффектов вне собственного хранилища.

Итоговая форма сигнатуры

defineDriver(driver: Driver, callback?: Function): Promise<void>

где Driver представляет строго определённый интерфейс с набором обязательных методов и идентификатором _driver, обеспечивающим интеграцию с системой хранилищ localForage.