IndexedDB на практике: хранение больших файлов и офлайн-архитектура в браузере

技术架构

Почему IndexedDB?

У вариантов хранения в браузере есть чёткие ограничения:

Вариант Ёмкость Типы данных Синхронный API Сценарий
Cookie ~4КБ Строка Идентификаторы сессий
localStorage ~5МБ Строка Простые настройки
sessionStorage ~5МБ Строка Временное состояние
IndexedDB Сотни МБ–ГБ Любые структурированные данные ❌ Async Большие файлы, офлайн-приложения

Для сайтов инструментов, которым нужно кэшировать в браузере промежуточные результаты обработки PDF, модули WASM или историю загрузок пользователей, IndexedDB — единственный жизнеспособный выбор.


Ключевые понятия

База данных → Object Store → Запись

Database: "toolsku-cache"
  ├── ObjectStore: "wasm-modules"     (key: moduleName)
  ├── ObjectStore: "file-cache"       (key: fileHash, index: timestamp)
  └── ObjectStore: "user-preferences" (key: settingKey)

Транзакции и параллелизм

Транзакции IndexedDB автофиксируются, и для каждого Object Store одновременно разрешена только одна транзакция чтения/записи:

const tx = db.transaction(['file-cache'], 'readwrite');
const store = tx.objectStore('file-cache');
await store.put({ hash: 'abc123', data: arrayBuffer, timestamp: Date.now() });
await tx.done; // Wait for transaction to complete

IndexedDB в ToolsKu

Кэширование модулей WASM

ffmpeg.wasm весит около 30 МБ и при каждой загрузке занимает 3–5 секунд. После кэширования в IndexedDB последующие посещения происходят почти мгновенно:

async function getWasmModule(name: string): Promise<ArrayBuffer> {
  const cached = await idb.get('wasm-modules', name);
  if (cached) return cached;

  const response = await fetch(`/wasm/${name}.wasm`);
  const buffer = await response.arrayBuffer();
  await idb.put('wasm-modules', buffer, name);
  return buffer;
}

Фрагментированное хранение больших файлов

Хранить файлы размером более 50 МБ в IndexedDB сразу целиком неидеально. Стратегия фрагментации:

File (200MB) → split into 4MB chunks → store each in IndexedDB
key: "file:{hash}:chunk:{index}"
Read in order and concatenate → restore full file

Миграция версий

Когда схема базы данных меняется, миграция выполняется в onupgradeneeded:

const request = indexedDB.open('toolsku-cache', 2); // version 2

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  if (event.oldVersion < 2) {
    db.createObjectStore('processing-history', { keyPath: 'id' });
  }
};

Лучшая практика: добавляйте только ObjectStore — никогда не удаляйте их. Увеличивайте номер версии для запуска миграции и избегайте удаления пользовательских данных.


IndexedDB против OPFS

Характеристика IndexedDB OPFS (Origin Private File System)
Зрелость API Широкая поддержка Chrome 86+ / Safari 15.2+
Модель чтения/записи Хранилище ключ-значение Настоящая файловая система
Производительность Умеренная Выше (особенно синхронный доступ)
Лучше всего для Структурированный кэш Ввод-вывод больших файлов

ToolsKu использует преимущественно IndexedDB, а OPFS — как оптимизацию производительности в Chrome.


Резюме

IndexedDB — важнейшая инфраструктура для офлайн-ориентированных браузерных инструментов. Хорошо спроектированные Object Store, кэширование WASM и стратегии фрагментированного хранения позволяют ToolsKu оставаться отзывчивым даже в медленных сетях.

Попробуйте эти локальные браузерные инструменты — регистрация не требуется →

#IndexedDB#浏览器存储#离线#大文件#架构