Объём хранилища и запросы на расширение

Хранилище, используемое через IndexedDB (и, как следствие, через библиотеку localForage), подчиняется системе квот, установленной браузером и операционной системой. Объём доступного пространства не является фиксированным и определяется динамически на основе нескольких факторов:

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

В отличие от традиционных серверных хранилищ, клиентское хранилище в браузере является разделяемым ограниченным ресурсом, и каждый origin получает лишь часть общего пула.

Пределы хранилища в IndexedDB

IndexedDB не задаёт жёсткого лимита на уровне спецификации. Ограничения вводятся реализациями браузеров:

  • Chrome / Chromium — динамическое выделение, часто до 60–80% свободного дискового пространства;
  • Firefox — более консервативное квотирование, основанное на проценте свободного места;
  • Safari — строгие ограничения, особенно на мобильных устройствах, с агрессивной очисткой данных.

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

localForage, как абстракция над IndexedDB, WebSQL и localStorage, наследует эти ограничения напрямую.

Поведение при достижении квоты

При превышении лимита хранилища IndexedDB генерирует ошибку квоты. В контексте localForage это проявляется через отклонённый Promise с ошибкой, связанной с записью данных.

Типичные сценарии:

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

На уровне браузера может быть инициировано внутреннее сжатие или очистка неиспользуемых данных, но это не гарантируется.

Запросы на увеличение хранилища

Современные браузеры предоставляют механизм запроса увеличения квоты через Storage API.

Основной метод:

navigator.storage && navigator.storage.persist()

Этот вызов переводит хранилище в режим постоянного хранения (persistent storage), уменьшая вероятность автоматического удаления данных при нехватке места.

Также доступна проверка статуса:

navigator.storage && navigator.storage.persisted()

Возвращаемое значение отражает, было ли хранилище уже переведено в постоянный режим.

Поведение persistent storage

Если браузер предоставляет согласие на постоянное хранение:

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

Однако даже persistent storage не гарантирует абсолютную защиту: при критическом дефиците дискового пространства данные могут быть удалены системой.

Квоты в разных режимах браузера

Режим приватного просмотра существенно изменяет поведение квотирования:

  • хранилище обычно ограничено объёмом оперативной памяти или временного диска;
  • данные удаляются автоматически после закрытия сессии;
  • запросы на persistent storage чаще всего игнорируются или отклоняются.

localForage в таком режиме работает поверх временного IndexedDB, что делает долговременное хранение невозможным.

Ошибки переполнения и их обработка

При работе с localForage важно учитывать специфические ошибки:

  • QuotaExceededError — превышение лимита;
  • InvalidStateError — невозможность записи из-за состояния базы;
  • UnknownError — общая ошибка движка хранения.

Такие ошибки возникают асинхронно и требуют обработки через .catch() или try/catch при использовании async/await.

try {
  await localforage.setItem('key', largeData);
} catch (e) {
  if (e.name === 'QuotaExceededError') {
    // обработка нехватки места
  }
}

Стратегии уменьшения потребления хранилища

При работе с ограниченными квотами применяется несколько практических подходов:

Сжатие данных

Перед записью данные сериализуются и сжимаются (например, gzip или lz-string). Это снижает нагрузку на IndexedDB, но увеличивает вычислительные затраты.

Фрагментация записей

Большие структуры разбиваются на несколько ключей:

  • вместо одного большого объекта хранится набор частей;
  • упрощается частичное обновление данных;
  • уменьшается вероятность единичного превышения квоты.

Очистка устаревших данных

Реализуется политика TTL (time-to-live):

  • данные получают временную метку;
  • периодически удаляются устаревшие записи;
  • уменьшается общий объём базы.

Контроль объёма перед записью

Хотя браузер не всегда предоставляет точные метрики, можно использовать:

navigator.storage && navigator.storage.estimate()

Этот метод возвращает приблизительный объём использования и доступного пространства.

Оценка доступного пространства

navigator.storage.estimate() возвращает объект:

  • usage — фактически занятое пространство;
  • quota — общий лимит для origin.

Разница между ними позволяет оценить запас перед записью. Однако значения являются приблизительными и могут изменяться между вызовами.

localForage не абстрагирует этот уровень, поэтому подобные проверки выполняются вручную на уровне приложения.

Особенности работы с большими объектами

IndexedDB способен хранить крупные бинарные данные (Blobs, ArrayBuffer), но производительность зависит от:

  • фрагментации базы;
  • реализации браузера;
  • доступного дискового пространства;
  • внутренней сериализации structured clone algorithm.

При увеличении объёма объектов растёт:

  • время записи;
  • время чтения;
  • вероятность блокировки основного потока при неаккуратной архитектуре.

localForage минимизирует часть этих проблем, но не устраняет ограничения движка.

Конкуренция за квоту между сайтами

Каждый origin имеет собственную квоту, но браузер может перераспределять ресурсы:

  • редко используемые сайты теряют часть выделенного объёма;
  • активные приложения получают больший приоритет;
  • при переполнении диска происходит глобальная очистка по LRU-подобной стратегии.

Это означает, что поведение хранилища нельзя считать стабильным в долгосрочной перспективе.

Согласованность данных при ограничениях

При работе на границе квоты важно учитывать возможные сценарии:

  • частично записанные данные;
  • откаты транзакций;
  • расхождение между кэшем и IndexedDB;
  • потеря последних изменений при ошибке записи.

localForage обеспечивает атомарность на уровне операций, но не гарантирует успешность записи при отсутствии ресурсов.

Поведение при миграции данных между драйверами

localForage может переключаться между IndexedDB, WebSQL и localStorage. При ограничениях:

  • localStorage имеет минимальную квоту (обычно 5–10 MB);
  • WebSQL зависит от реализации и считается устаревшим;
  • IndexedDB предоставляет наибольший объём.

При нехватке места fallback на localStorage часто приводит к ошибкам переполнения значительно быстрее, чем в IndexedDB.

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

Эффективная работа с ограничениями строится на комбинировании нескольких уровней:

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

Такой подход делает систему хранения устойчивой к изменяющимся ограничениям браузеров и операционной среды.