Библиотека localForage построена как абстракция над различными механизмами хранения данных в браузере. Её ключевая идея заключается в том, чтобы автоматически выбирать наиболее подходящее хранилище и предоставлять единый асинхронный API независимо от реальной реализации.
Внутри экосистемы браузерного хранения данных обычно рассматриваются три основных уровня:
Именно последний вариант — localStorage — играет критическую роль в сценарии деградации возможностей, когда более мощные хранилища недоступны или не могут быть использованы.
localForage использует концепцию драйверов. Каждый драйвер — это адаптер, реализующий единый интерфейс:
При инициализации библиотека пытается выбрать драйвер по приоритету:
Таким образом, localStorage находится на последнем месте цепочки и рассматривается исключительно как fallback-механизм.
Переход на localStorage происходит только в строго определённых ситуациях, когда более предпочтительные технологии оказываются недоступны.
Основная причина активации fallback-режима:
В этом случае localForage пытается подключить WebSQL, и только затем localStorage.
Даже при наличии поддержки IndexedDB возможны ситуации, когда инициализация завершается ошибкой:
Если IndexedDBDriver не может открыть базу или создать object store, происходит переход к следующему драйверу.
В некоторых режимах браузеры ограничивают доступ к долговременному хранилищу:
Если IndexedDB или WebSQL не могут гарантировать запись, localStorage остаётся единственным синхронным вариантом.
Разработчик может явно указать использование localStorage:
localforage.setDriver(localforage.LOCALSTORAGE)
В этом случае остальные драйверы игнорируются полностью.
Когда localForage переходит на localStorage, поведение библиотеки меняется на фундаментальном уровне, несмотря на сохранение API.
localStorage работает синхронно, в отличие от IndexedDB:
localForage вынужден оборачивать эти операции в Promise, но фактическая работа остаётся синхронной.
localStorage имеет строгие лимиты, зависящие от браузера:
localForage не может обойти эти ограничения, поэтому при переходе на
localStorage резко возрастает риск ошибок
QuotaExceededError.
localStorage хранит только строки, поэтому:
localForage выполняет сериализацию автоматически, но это добавляет накладные расходы.
localStorage не предоставляет асинхронного API, поэтому localForage создаёт адаптер, который имитирует поведение IndexedDB-драйвера.
Каждая операция выглядит следующим образом:
Это создаёт иллюзию асинхронности:
setItem(key, value) {
return new Promise((resolve) => {
localStorage.setItem(key, serialize(value))
resolve(value)
})
}
При переключении на localStorage наблюдаются важные изменения:
Особенно заметно при массовых операциях iterate и
setItem.
localForage в IndexedDB использует транзакции для целостности данных, но при localStorage:
IndexedDB поддерживает конкурентный доступ, localStorage — нет:
Внутренний алгоритм localForage можно представить как последовательность проверок:
localStorage используется только при полном провале предыдущих уровней.
Несмотря на то, что localStorage считается fallback-решением, есть реальные сценарии, где он фактически становится основным:
Иногда разработчики сознательно ограничивают стек:
Использование localStorage как fallback накладывает ограничения на всю архитектуру localForage:
Эти ограничения не устраняются библиотекой, а лишь изолируются через единый API.
localForage допускает динамическое переключение драйверов, но переход на localStorage сопровождается рядом нюансов:
Поэтому смена драйвера обычно рассматривается как инициализационный процесс, а не runtime-операция.
localStorage требует строкового представления, поэтому localForage использует слой сериализации:
Однако при переходе на localStorage:
В отличие от IndexedDB, ошибки localStorage носят более ограниченный характер:
localForage не имеет возможности компенсировать эти ошибки, поэтому они пробрасываются через Promise rejection.
localStorage в localForage выполняет строго определённую функцию:
Он не рассматривается как полноценное хранилище, а выступает как последний слой деградации, обеспечивающий сохранение базовой функциональности при отсутствии современных браузерных API.