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 оставаться отзывчивым даже в медленных сетях.
Попробуйте эти локальные браузерные инструменты — регистрация не требуется →