QuotaExceededError: обнаружение и реакция

Idb-keyval — это лёгкая библиотека для работы с IndexedDB в браузере, которая предоставляет простой API для сохранения, получения и удаления данных. Одним из ключевых аспектов при использовании IndexedDB является ограничение на объём хранимых данных, что может привести к ошибке QuotaExceededError. Эта ошибка возникает, когда попытка записи данных превышает доступное хранилище браузера.

Причины возникновения QuotaExceededError

  1. Превышение лимита хранилища Каждый браузер накладывает ограничения на объём данных, которые можно хранить в IndexedDB. Обычно лимит составляет несколько сотен мегабайт на домен, но точное значение зависит от конкретного браузера и устройства.

  2. Множественные записи больших объектов Даже если отдельный объект небольшой, последовательные записи большого количества данных могут суммарно превысить лимит, что приводит к QuotaExceededError.

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

Обнаружение QuotaExceededError

Idb-keyval использует промисы для всех операций записи (set, update, del). Ошибку QuotaExceededError можно отлавливать через конструкцию try/catch с асинхронной обработкой промисов:

import { set } from 'idb-keyval';

async function saveData(key, value) {
    try {
        await set(key, value);
        console.log('Данные успешно сохранены');
    } catch (err) {
        if (err.name === 'QuotaExceededError') {
            console.error('Ошибка: превышен лимит хранилища');
        } else {
            console.error('Произошла другая ошибка:', err);
        }
    }
}

Ключевой момент: проверка должна выполняться по свойству name ошибки, а не по тексту сообщения, так как разные браузеры формируют сообщение по-своему.

Реакция на QuotaExceededError

1. Очистка ненужных данных Перед повторной попыткой записи можно удалить старые или неиспользуемые ключи:

import { del } from 'idb-keyval';

await del('старый_ключ');

2. Сжатие данных Использование сжатия JSON-объектов (например, с помощью библиотек lz-string) помогает снизить занимаемый объём:

import LZString from 'lz-string';

const compressed = LZString.compress(JSON.stringify(largeObject));
await set('key', compressed);

3. Разделение данных на части Если объект слишком большой, его можно разбить на несколько частей и сохранять по отдельным ключам:

const chunkSize = 1024 * 100; // 100 KB
const chunks = [];

for (let i = 0; i < data.length; i += chunkSize) {
    chunks.push(data.slice(i, i + chunkSize));
}

for (let j = 0; j < chunks.length; j++) {
    await set(`data_part_${j}`, chunks[j]);
}

4. Отслеживание доступного объёма Для современных браузеров возможно использование API navigator.storage.estimate() для оценки оставшегося пространства:

const { usage, quota } = await navigator.storage.estimate();
console.log(`Использовано: ${usage} / Доступно: ${quota}`);

Этот метод позволяет принимать решение о необходимости сжатия или удалении данных до записи.

Обработка QuotaExceededError в массовых сценариях

При работе с большим количеством данных важно предусматривать стратегию отказоустойчивости:

  • Пакетная запись – разбивать данные на небольшие блоки, чтобы уменьшить риск превышения лимита.
  • Приоритет хранения – сохранять сначала критически важные данные, а менее важные отложить или сжать.
  • Логирование ошибок – фиксировать случаи QuotaExceededError для последующего анализа использования хранилища.

Итоговая структура кода для безопасной записи

import { set, del } from 'idb-keyval';
import LZString from 'lz-string';

async function safeSet(key, value) {
    try {
        const compressed = LZString.compress(JSON.stringify(value));
        await set(key, compressed);
    } catch (err) {
        if (err.name === 'QuotaExceededError') {
            console.warn('Превышен лимит хранилища, очищаем старые данные...');
            await del('old_key'); // удаление устаревших данных
            await set(key, compressed); // повторная попытка
        } else {
            throw err;
        }
    }
}

Такой подход минимизирует вероятность потери данных и позволяет управлять лимитами браузерного хранилища в приложениях, использующих Idb-keyval.