Инициализация localForage представляет собой цепочку асинхронных операций выбора и активации подходящего драйвера хранения, проверки доступности API браузера и подготовки внутреннего состояния хранилища. Ошибки на этом этапе имеют принципиально иной характер, чем ошибки при чтении или записи данных: они блокируют работу всей абстракции и требуют централизованной стратегии обработки.
Поведение localForage зависит от среды выполнения, и именно эта зависимость формирует основные классы ошибок.
1. Недоступность IndexedDB
IndexedDB является предпочтительным драйвером в современных браузерах, однако его доступность не гарантирована:
В таких случаях попытка инициализации драйвера приводит к отказу и переходу к следующему варианту (WebSQL или localStorage), если он указан.
2. Ограничения приватного режима браузера
Особенно критичным является Safari (iOS/macOS), где в приватном режиме IndexedDB может:
Это приводит к трудноуловимым ошибкам инициализации, которые проявляются только в рантайме.
3. Отсутствие доступных драйверов
Если разработчик явно задаёт список драйверов:
localforage.setDriver([
localforage.INDEXEDDB,
localforage.WEBSQL
]);
и ни один из них не поддерживается окружением, инициализация завершается ошибкой. Это один из самых предсказуемых, но часто игнорируемых сценариев.
4. Нарушение контекста безопасности
IndexedDB и часть современных storage API требуют защищённого контекста:
При нарушении этих условий драйвер не может быть активирован.
5. Ошибки во время открытия хранилища
Даже при наличии поддержки API возможны ошибки:
Инициализация localForage основана на цепочке Promise:
Ключевой точкой синхронизации является метод:
localforage.ready()
Он возвращает Promise, который:
Основной способ отлова ошибок инициализации — обработка отклонения Promise:
localforage.ready()
.then(() => {
// storage готов к работе
})
.catch((err) => {
console.error('Ошибка инициализации storage:', err);
});
Такой подход охватывает:
Важно, что ready() не следует путать с синхронной
инициализацией: к моменту вызова Promise библиотека уже может быть
частично настроена, но не гарантирует работоспособность backend.
При ручном указании драйверов обработка ошибок становится более предсказуемой, но требует явного контроля:
async function initStorage() {
try {
await localforage.setDriver([
localforage.INDEXEDDB,
localforage.WEBSQL,
localforage.LOCALSTORAGE
]);
await localforage.ready();
} catch (err) {
console.error('Не удалось инициализировать localForage:', err);
}
}
В этом сценарии ошибки могут возникать:
Практическая обработка ошибок почти всегда включает резервные варианты поведения.
1. Переход на in-memory storage
Если все драйверы недоступны, возможно использование временного хранилища:
class MemoryStore {
constructor() {
this.store = new Map();
}
getItem(key) {
return Promise.resolve(this.store.get(key) || null);
}
setItem(key, value) {
this.store.set(key, value);
return Promise.resolve(value);
}
removeItem(key) {
this.store.delete(key);
return Promise.resolve();
}
}
2. Деградация функциональности
При отсутствии persistent storage система может:
3. Повторная инициализация
В некоторых случаях ошибка носит временный характер:
async function initWithRetry(retries = 3) {
for (let i = 0; i < retries; i++) {
try {
await localforage.ready();
return;
} catch (e) {
if (i === retries - 1) throw e;
await new Promise(r => setTimeout(r, 200 * (i + 1)));
}
}
}
Метод setDriver() часто становится источником ошибок,
которые воспринимаются как «инициализация не работает»:
Типичный сценарий неправильного использования:
localforage.setItem('key', 'value'); // ранний вызов
localforage.setDriver([...]); // поздняя инициализация
Это может приводить к частично неконсистентному состоянию.
Инициализация storage должна завершаться до начала любых операций чтения/записи. В противном случае возникает гонка состояний.
Корректный паттерн:
let storageReady;
function getStorage() {
if (!storageReady) {
storageReady = localforage.ready();
}
return storageReady;
}
async function safeSet(key, value) {
await getStorage();
return localforage.setItem(key, value);
}
Такой подход гарантирует:
В крупных приложениях обработка ошибок localForage обычно выносится в отдельный слой абстракции:
class StorageService {
constructor() {
this.initPromise = null;
}
init() {
if (!this.initPromise) {
this.initPromise = localforage.ready().catch((err) => {
this.handleInitError(err);
throw err;
});
}
return this.initPromise;
}
handleInitError(err) {
console.error('Storage init failed:', err);
// telemetry hook
// sendToMonitoring(err);
}
async set(key, value) {
await this.init();
return localforage.setItem(key, value);
}
}
Такой слой позволяет:
Ошибки инициализации относятся к критическому классу событий и должны фиксироваться отдельно от обычных ошибок хранения.
Рекомендуемые поля логирования:
Это особенно важно при анализе:
Некоторые сценарии приводят к состоянию, когда localForage:
В таких случаях возможны:
Для предотвращения таких ситуаций используется явная проверка:
await localforage.ready();
const driver = localforage.driver();
Надёжная инициализация localForage в нестабильной среде строится на сочетании трёх принципов:
ready() перед любыми операциями;Эта модель снижает вероятность критических ошибок до уровня, при котором storage становится предсказуемым даже в ограниченных браузерных окружениях.