Пример минимального кастомного драйвера

Кастомный драйвер в localForage представляет собой объект, реализующий строго определённый интерфейс хранения данных. Его задача — обеспечить единый API (getItem, setItem, removeItem, clear и др.) поверх любого механизма хранения: памяти, IndexedDB, WebSQL, cookies или внешнего API.

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


Общая структура драйвера

Любой драйвер localForage обязан содержать:

  • уникальный идентификатор _driver

  • метод проверки поддержки _support

  • инициализацию _initStorage

  • базовые операции CRUD:

    • getItem
    • setItem
    • removeItem
    • clear
    • length
    • key

Дополнительно могут присутствовать методы итерации и расширенные API, но для минимального драйвера они не обязательны.


Минимальный in-memory драйвер

Простейшая реализация строится на обычном объекте JavaScript, который используется как словарь ключ-значение.

const MemoryDriver = {
  _driver: 'memoryDriver',

  _initStorage: function (options) {
    this._store = {};
    this._config = options || {};
    return Promise.resolve();
  },

  _support: function () {
    return true;
  },

  getItem: function (key) {
    const value = this._store[key];
    return Promise.resolve(value === undefined ? null : value);
  },

  setItem: function (key, value) {
    this._store[key] = value;
    return Promise.resolve(value);
  },

  removeItem: function (key) {
    delete this._store[key];
    return Promise.resolve();
  },

  clear: function () {
    this._store = {};
    return Promise.resolve();
  },

  length: function () {
    return Promise.resolve(Object.keys(this._store).length);
  },

  key: function (n) {
    const keys = Object.keys(this._store);
    return Promise.resolve(keys[n] || null);
  }
};

Требования к интерфейсу драйвера

localForage ожидает, что все методы драйвера будут возвращать Promise. Даже синхронные операции должны быть обёрнуты в промисы, поскольку библиотека унифицирует асинхронное поведение независимо от backend-хранилища.

Ключевые требования:

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

Регистрация кастомного драйвера

После создания объекта драйвера он регистрируется в localForage через defineDriver.

import localForage from 'localforage';

localForage.defineDriver(MemoryDriver);

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

localForage.setDriver('memoryDriver');

Минимальный жизненный цикл драйвера

При использовании кастомного драйвера localForage проходит несколько этапов:

  1. Проверка поддержки Вызывается _support, чтобы определить, можно ли использовать драйвер в текущей среде.

  2. Инициализация _initStorage создаёт внутренние структуры хранения.

  3. Операции чтения/записи getItem и setItem используются для доступа к данным.

  4. Управление данными removeItem, clear, length, key обеспечивают контроль состояния хранилища.


Поведение хранения данных

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

this._store = {};

Она ведёт себя как:

  • ключи — строки
  • значения — любые сериализуемые данные
  • отсутствие ключа трактуется как undefined, но наружу возвращается null

Такое поведение соответствует стандарту localForage, где null используется как универсальный маркер отсутствия значения.


Особенности реализации Promise-обёртки

Даже в синхронной реализации важно сохранять асинхронный контракт:

return Promise.resolve(value);

Это обеспечивает:

  • совместимость с IndexedDB-драйвером
  • предсказуемость цепочек .then()
  • отсутствие блокировки основного потока выполнения

Минимизация интерфейса: допустимые сокращения

Для учебных целей можно оставить только строго необходимые методы:

  • _driver
  • _initStorage
  • _support
  • getItem
  • setItem
  • removeItem
  • clear

Методы length и key формально не обязательны для самой базовой работы, но без них теряется совместимость с частью API localForage, использующей перечисление ключей.


Интеграция с localForage instance

После установки драйвера можно создать отдельный экземпляр, использующий только его:

const store = localforage.createInstance({
  name: 'memory-db',
  driver: 'memoryDriver'
});

Такой экземпляр полностью изолирован от IndexedDB и других встроенных драйверов.


Поведение при повторной инициализации

Каждый вызов _initStorage должен сбрасывать внутреннее состояние:

this._store = {};

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


Ошибки и устойчивость

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

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

При необходимости можно расширить поведение через Promise.reject(new Error(...)), но в минимальной версии это не требуется.


Расширение минимального драйвера

Хотя базовая реализация использует объект, её можно постепенно расширять:

  • замена на Map для предсказуемого порядка ключей
  • добавление сериализации данных
  • внедрение TTL (time-to-live)
  • прокси на IndexedDB или внешнее API

Однако базовый контракт localForage остаётся неизменным: асинхронные методы, ключ-значение модель и строгая совместимость интерфейса драйвера.