Стоимость операций чтения и записи по драйверам

localForage строится как единый API поверх нескольких механизмов хранения: IndexedDB, WebSQL и localStorage. Абстракция скрывает различия, но стоимость операций чтения и записи определяется не библиотекой, а конкретным драйвером и его внутренней моделью работы с данными.

Стоимость операции в данном контексте включает:

  • время сериализации и десериализации значений;
  • накладные расходы на транзакции;
  • стоимость обращения к диску или синхронному хранилищу;
  • задержки event loop и очередей задач;
  • ограничения на блокировки потока выполнения.

localStorage: синхронные операции и скрытая дороговизна

localStorage является самым простым, но одновременно самым проблемным по производительности драйвером.

Стоимость записи

Операция записи в localStorage включает:

  • синхронную сериализацию значения в строку (обычно JSON.stringify);
  • синхронную запись в память браузера;
  • немедленную блокировку основного потока.

Ключевой фактор стоимости — блокировка UI thread. Даже небольшие объёмы данных приводят к заметным задержкам, поскольку:

  • запись выполняется синхронно;
  • отсутствует транзакционная модель;
  • каждое изменение вызывает перерасчёт внутреннего хранилища браузера.

При увеличении объёма данных стоимость растёт нелинейно, так как многие браузеры пересобирают внутренний storage snapshot целиком.

Стоимость чтения

Чтение также синхронно:

  • извлечение строки из памяти;
  • JSON.parse;
  • возврат результата.

Основная нагрузка возникает на этапе десериализации, особенно при:

  • глубоко вложенных структурах;
  • больших массивах;
  • частых вызовах getItem.

Особенности

  • отсутствует асинхронность;
  • нет транзакций;
  • высокая стоимость при массовых операциях;
  • быстрый старт, но плохая масштабируемость.

IndexedDB: асинхронная модель с транзакционной стоимостью

IndexedDB — основной драйвер localForage в современных браузерах. Он обеспечивает наилучший баланс между производительностью и масштабируемостью, но имеет более сложную модель стоимости операций.

Стоимость записи

Запись в IndexedDB включает несколько этапов:

  • создание или использование транзакции;
  • структурное клонирование объекта (structured clone algorithm);
  • запись в B-tree структуру хранилища;
  • флаш транзакции на диск (не всегда мгновенный).

Главная статья расходов — structured clone. Этот процесс:

  • создаёт глубокую копию объекта;
  • сериализует поддерживаемые типы (ArrayBuffer, Date, Map и др.);
  • может быть существенно медленнее JSON-сериализации для простых структур;
  • увеличивает стоимость пропорционально глубине и размеру объекта.

Дополнительные затраты:

  • создание транзакции (особенно при частых одиночных записях);
  • блокировки object store на время транзакции;
  • дисковая синхронизация при commit.

Стоимость чтения

Чтение состоит из:

  • открытия транзакции;
  • поиска ключа в B-tree индексе;
  • восстановления объекта через structured clone обратно в JS-объект.

Основные затраты:

  • поиск в индексе (логарифмическая сложность);
  • десериализация structured clone;
  • асинхронный переход через event loop.

Чтение обычно быстрее записи, поскольку отсутствует необходимость модификации структуры хранения, но при больших объектах стоимость clone остаётся значительной.


WebSQL: устаревшая, но предсказуемая модель стоимости

WebSQL основан на SQLite и использует SQL-запросы для работы с данными. Хотя технология устарела, её поведение всё ещё встречается в некоторых WebView.

Стоимость записи

Операция записи включает:

  • выполнение SQL INSERT/UPDATE;
  • сериализацию данных (часто в TEXT/BLOB);
  • блокировки таблиц или страниц SQLite;
  • запись WAL (Write-Ahead Logging) или прямую модификацию файла.

Стоимость зависит от:

  • сложности схемы;
  • наличия индексов;
  • размера BLOB.

Преимущество WebSQL — предсказуемая дисковая модель: стоимость растёт более линейно, чем в localStorage, и менее зависима от JS-объектов.

Стоимость чтения

Чтение включает:

  • выполнение SQL SELECT;
  • использование индексов;
  • десериализацию результата.

Основные затраты:

  • парсинг SQL;
  • доступ к файлу базы;
  • преобразование строк/Blob в JS-структуры.

WebSQL часто быстрее localStorage при больших объёмах данных, но уступает IndexedDB по параллелизму.


Сравнение стоимости операций по драйверам

Запись одного объекта

  • localStorage: минимальные накладные расходы, но полная блокировка потока
  • IndexedDB: высокая стоимость structured clone, но неблокирующая модель
  • WebSQL: средняя стоимость с дисковой записью и SQL overhead

Чтение одного объекта

  • localStorage: очень быстро для малых данных, но синхронная блокировка
  • IndexedDB: асинхронный доступ с B-tree поиском
  • WebSQL: SQL-запрос + доступ к файлу

Массовые операции записи

localStorage

Массовая запись резко ухудшает производительность:

  • каждая операция блокирует main thread;
  • браузер может пересобирать storage snapshot;
  • отсутствует batching на уровне API.

Стоимость растёт пропорционально количеству вызовов без оптимизации.

IndexedDB

Поддерживает эффективные батчи через транзакции:

  • одна транзакция на множество записей значительно дешевле;
  • уменьшается overhead создания transaction;
  • disk flush может быть отложен браузером.

Ключевой фактор — группировка операций.

WebSQL

SQL позволяет:

  • использовать batch INSERT;
  • выполнять транзакции на уровне SQL BEGIN/COMMIT;
  • минимизировать дисковые операции.

Стоимость сериализации и клонирования

localForage не использует единый формат хранения, но все драйверы сталкиваются с преобразованием JS-объектов.

JSON-сериализация (localStorage)

  • линейная сложность O(n);
  • высокая скорость для простых объектов;
  • деградация при циклических или вложенных структурах (через обход ограничений).

Structured Clone (IndexedDB)

  • поддерживает сложные типы данных;
  • дороже JSON.stringify для простых структур;
  • эффективнее для бинарных данных и сложных объектов.

Влияние размера данных на стоимость

Малые объекты (до нескольких КБ)

  • localStorage: минимальная стоимость
  • IndexedDB: overhead транзакции может быть выше полезной работы
  • WebSQL: сопоставим с IndexedDB

Средние объекты (десятки-сотни КБ)

  • IndexedDB начинает выигрывать за счёт асинхронности
  • localStorage становится заметно медленным
  • WebSQL сохраняет стабильность

Большие объекты (МБ и выше)

  • localStorage практически непригоден
  • IndexedDB оптимален благодаря потоковой архитектуре браузера
  • WebSQL зависит от реализации SQLite и может деградировать при блокировках

Транзакционная стоимость IndexedDB

IndexedDB вводит отдельную категорию стоимости — управление транзакциями.

Каждая транзакция включает:

  • создание контекста;
  • блокировку object store;
  • очередь операций;
  • commit/abort стадии.

Стоимость возрастает при:

  • множественных коротких транзакциях;
  • конкуренции за один object store;
  • частых read/write interleaving.

Оптимальная модель — минимизация числа транзакций при сохранении логической целостности операций.


Стоимость конкурентного доступа

localStorage

  • отсутствует конкурентная модель;
  • изменения синхронны;
  • возможны race conditions между вкладками через storage events.

IndexedDB

  • поддерживает параллельные транзакции;
  • блокировка на уровне object store;
  • конфликтность приводит к queueing операций.

WebSQL

  • блокировки таблиц;
  • последовательное выполнение SQL в транзакциях.

Энергетическая и системная стоимость

Хотя браузеры не предоставляют прямых метрик энергопотребления, косвенно:

  • localStorage увеличивает CPU load из-за блокировки main thread;
  • IndexedDB снижает нагрузку на UI, но увеличивает I/O активность;
  • WebSQL создаёт равномерную нагрузку на диск и CPU.

Итоговая модель оценки стоимости

Стоимость операции можно формализовать как сумму компонентов:

  • T_serialization — сериализация данных;
  • T_transaction — создание и управление транзакцией;
  • T_io — дисковая или memory I/O операция;
  • T_clone — структурное копирование;
  • T_eventloop — задержки планировщика задач.

Для каждого драйвера распределение этих компонентов различается:

  • localStorage: доминирует T_serialization + блокировка T_eventloop;
  • IndexedDB: доминирует T_clone + T_transaction;
  • WebSQL: доминирует T_io + SQL parsing overhead.

Поведенческие последствия различий стоимости

Различия в стоимости операций напрямую влияют на архитектуру приложений:

  • частые мелкие записи становятся критичными для localStorage;
  • IndexedDB требует оптимизации транзакционных границ;
  • WebSQL требует минимизации SQL round-trips.

Эти различия определяют не только производительность, но и устойчивость приложения под нагрузкой, особенно при активной работе с offline-first сценариями и синхронизацией состояния.