Регистрация кастомного драйвера в localForage всегда происходит как последовательность строгих шагов, где порядок определяет не только доступность хранилища, но и то, какой механизм сохранения данных будет выбран в рантайме. В основе лежит принцип: драйвер сначала описывается, затем регистрируется в системе, после чего становится частью цепочки выбора хранилища.
Внутренняя архитектура localForage построена вокруг абстракции драйвера как набора методов, соответствующих единым контрактам. Любой кастомный драйвер обязан реализовать базовые операции: инициализацию, чтение, запись, удаление и очистку данных. Однако до момента регистрации он не участвует в выборе backend’а.
Ключевая особенность заключается в том, что регистрация драйвера не означает его автоматическое использование. Она лишь добавляет его в глобальный реестр доступных решений внутри экземпляра localForage.
Первый этап — создание объекта драйвера:
_initStorage,
getItem, setItem, removeItem,
clear, length, key,
keys, iterate)_support или supports
(в зависимости от реализации), который отвечает за проверку
совместимости окруженияdriverНа этом этапе драйвер существует только как JavaScript-объект и не связан с системой localForage.
Пример структуры:
const CustomDriver = {
_driver: 'customDriver',
_initStorage: function(options) {},
getItem: function(key) {},
setItem: function(key, value) {},
removeItem: function(key) {},
clear: function() {},
length: function() {},
key: function(n) {},
keys: function() {},
iterate: function(callback) {},
_support: function() {
return true;
}
};
Регистрация осуществляется через defineDriver. Этот
метод добавляет драйвер в глобальный пул доступных хранилищ.
import localForage from 'localforage';
localForage.defineDriver(CustomDriver);
После выполнения этого вызова драйвер становится известен системе, но не активируется для существующих экземпляров автоматически.
Важный момент: регистрация должна происходить до попытки установки
драйвера через setDriver. Если попытка использовать драйвер
происходит раньше, система не сможет его найти в реестре и выбросит
ошибку.
Каждый экземпляр localForage имеет собственную цепочку выбора
драйвера. Она формируется через createInstance:
const store = localForage.createInstance({
name: 'appStorage',
driver: [
CustomDriver._driver,
localForage.INDEXEDDB,
localForage.WEBSQL
]
});
Порядок в массиве driver критически важен. Он определяет
приоритет использования:
Система последовательно проверяет поддержку каждого драйвера через
его _support и выбирает первый подходящий.
Регистрация (defineDriver) и активация
(setDriver) — это разные стадии жизненного цикла.
defineDriver добавляет реализацию в системуsetDriver активирует драйвер для конкретного
экземпляраawait localForage.defineDriver(CustomDriver);
const store = localForage.createInstance({
driver: [CustomDriver._driver]
});
await store.setDriver(CustomDriver._driver);
Если драйвер не был зарегистрирован до вызова setDriver,
система не сможет разрешить его имя в конкретную реализацию.
И регистрация, и установка драйвера являются асинхронными операциями. Это связано с тем, что некоторые драйверы требуют инициализации внешних API (например, IndexedDB или WebSQL).
Порядок выполнения:
defineDriver)createInstance)setDriver)_initStorageТолько после завершения _initStorage драйвер считается
полностью готовым к работе.
Перед тем как драйвер будет выбран, localForage вызывает его метод проверки поддержки. Этот этап встроен в механизм выбора и выполняется автоматически.
_support: function() {
try {
return typeof window !== 'undefined';
} catch (e) {
return false;
}
}
Если _support возвращает false, драйвер
исключается из цепочки, даже если он указан первым в приоритетах.
Когда в конфигурации задан массив драйверов, система проходит по нему сверху вниз. Логика следующая:
Это означает, что порядок массива фактически формирует стратегию устойчивости приложения.
driver: [
CustomDriver._driver,
localForage.INDEXEDDB,
localForage.LOCALSTORAGE
]
В такой конфигурации кастомный драйвер становится первым кандидатом, а встроенные — резервными.
Повторный вызов defineDriver для уже зарегистрированного
драйвера не приводит к созданию новой сущности. Внутренний реестр
localForage предотвращает дублирование, сохраняя ссылку на первую версию
реализации.
Это важно учитывать при динамической загрузке модулей, когда код может быть импортирован несколько раз.
Каждый экземпляр localForage имеет собственный контекст, но использует общий реестр драйверов. Это означает:
createInstance не влияет на другие
экземплярыТаким образом, один и тот же кастомный драйвер может использоваться в разных конфигурациях с различными приоритетами.
На практике наиболее частые проблемы возникают из-за нарушения последовательности:
setDriver до defineDriver_driver имени в конфигурацииdriver_initStorageТакие ошибки почти всегда связаны не с реализацией, а с порядком инициализации.
Порядок драйверов влияет не только на устойчивость, но и на производительность. Более быстрые хранилища должны стоять выше в списке приоритетов. Например, IndexedDB обычно предпочтительнее WebSQL или LocalStorage, и кастомные драйверы, использующие оптимизированные API, должны быть первыми в цепочке.
При неправильной расстановке приоритетов приложение может:
При использовании ленивой загрузки модулей регистрация драйвера часто происходит в runtime. В этом случае критично обеспечить завершение регистрации до создания экземпляров:
await import('./customDriver.js');
await localForage.defineDriver(CustomDriver);
const store = localForage.createInstance({
driver: [CustomDriver._driver]
});
await store.setDriver(CustomDriver._driver);
Несоблюдение этого порядка приводит к состоянию, когда экземпляр инициализируется с неполным набором драйверов и вынужден переходить на fallback.
Вся система подключения кастомного драйвера сводится к трём уровням порядка:
createInstance: определяет приоритет
выбораЭти три слоя формируют единую модель, в которой корректная последовательность определяет предсказуемость поведения хранилища и стабильность работы приложения.