Внутренняя модель хранения данных в localForage строится вокруг унифицированного слоя сериализации, который позволяет одинаково работать с различными бэкендами (IndexedDB, WebSQL, localStorage). При выборе WebSQL в качестве драйвера ключевую роль играет преобразование пользовательских значений в формат, совместимый с SQL-таблицами, где данные хранятся в виде строк или бинарных представлений.
WebSQL не предоставляет нативной поддержки сложных JavaScript-типов, поэтому localForage вынужден приводить все значения к сериализуемому виду, сохраняя при этом возможность обратного восстановления структуры данных.
Основная задача слоя сериализации — преобразовать произвольное JavaScript-значение в строку, которая может быть безопасно сохранена в таблице WebSQL и затем восстановлена без потери информации.
В основе лежит комбинация двух операций:
В большинстве случаев используется JSON-подобный механизм, но с дополнительной обвязкой для поддержки нестандартных типов.
В WebSQL localForage использует таблицу примерно следующей структуры:
Ключ хранится в виде строки без изменений, тогда как значение проходит сериализацию.
Основной механизм — это JSON.stringify. Он применяется
для большинства стандартных типов:
Пример:
localForage.setItem('user', { name: 'Alex', age: 30 });
В WebSQL это превращается в:
INS ERT INTO store (key, val ue)
VALUES ('user', '{"name":"Alex","age":30}')
JSON не поддерживает:
Поэтому localForage применяет дополнительные механизмы упаковки данных.
Для сохранения типа значения localForage использует внутренний слой упаковки. Значение может быть преобразовано в объект-обёртку, содержащий метаданные:
Пример внутреннего представления:
{
"value": "{\"year\":2025}",
"type": "object",
"dataType": "json"
}
Такая структура позволяет различать:
Date при сериализации теряет свою сущность и превращается в строку ISO или timestamp. localForage решает эту проблему через явную маркировку типа.
При сохранении:
localForage.setItem('time', new Date());
В WebSQL может храниться:
{
"value": 1717420000000,
"type": "date"
}
При извлечении выполняется восстановление:
new Date(1717420000000)
Таким образом достигается частичная типовая сохранность поверх JSON-ограничений.
WebSQL способен хранить BLOB, однако localForage чаще приводит бинарные данные к строковому виду.
Для ArrayBuffer и Blob используется один из подходов:
Пример:
{
value: "dat a:application/octet-stream;base64,AAABAAE...",
type: "arraybuffer"
}
При восстановлении происходит обратное декодирование base64 в бинарный буфер.
Поскольку WebSQL оперирует SQL-запросами, важной частью сериализации является защита от:
localForage не формирует SQL через конкатенацию пользовательских данных напрямую. Вместо этого применяются параметризованные запросы:
db.executeSql(
'INS ERT INTO store (key, val ue) VALUES (?, ?)',
[key, serializedValue]
);
Сериализованное значение предварительно проходит экранирование на уровне драйвера.
При вызове getItem происходит обратный процесс:
Алгоритм можно представить следующим образом:
При невозможности сериализации возникает несколько сценариев:
JSON.stringify выбрасывает ошибку (циклические
ссылки)localForage обычно:
Циклические структуры не поддерживаются и требуют ручного преобразования перед сохранением.
Сериализация и десериализация в WebSQL-драйвере являются значительной частью стоимости операций ввода-вывода.
Основные факторы влияния:
Особенно затратными являются:
В отличие от IndexedDB, где многие структуры поддерживаются нативно, WebSQL требует полного приведения к строке.
Это приводит к следующим последствиям:
IndexedDB может хранить объекты напрямую, тогда как WebSQL всегда работает через строковое представление.
localForage скрывает различия между драйверами через единый интерфейс:
Сериализация является частью драйвер-специфичной реализации, где WebSQL-драйвер содержит собственный слой:
Этот слой обеспечивает совместимость API независимо от ограничений SQL-хранилища.
Ключи в WebSQL хранятся без сериализации, но могут быть дополнены namespace-префиксом:
Это позволяет разделять несколько инстансов localForage внутри одной базы WebSQL.
Сериализация в WebSQL-драйвере ориентирована на обратную совместимость:
Это достигается за счёт слабосвязанной схемы упаковки данных, где основным является поле value, а дополнительные поля опциональны.
Поскольку WebSQL:
localForage вынужден сохранять консервативную стратегию сериализации:
Это делает сериализацию предсказуемой, но менее эффективной по сравнению с нативными объектными хранилищами.