Очистка хранилища: clear()

Метод clear() представляет собой одну из наиболее радикальных операций над таблицей в IndexedDB-обёртке Dexie.js. Он полностью удаляет все записи из указанного хранилища, сохраняя при этом саму структуру таблицы, индексы и схему базы данных. В отличие от последовательного удаления записей через delete() или фильтрации через where().delete(), операция clear() выполняется атомарно и значительно быстрее за счёт особенностей внутреннего механизма IndexedDB.

Синтаксис

table.clear()

Метод вызывается на экземпляре таблицы Dexie и возвращает Promise, который резолвится после завершения операции очистки.

await db.users.clear();

Также возможно использование в цепочке транзакций:

await db.transaction('rw', db.users, async () => {
  await db.users.clear();
});

Поведение метода

Операция clear() выполняет полное удаление всех записей из таблицы без необходимости их предварительного чтения. Это принципиально отличает её от обходных методов удаления.

Внутренне IndexedDB использует оптимизированную операцию очистки object store, что делает выполнение clear() практически мгновенным даже на больших объёмах данных.

Ключевые характеристики поведения:

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

Возвращаемое значение

Метод возвращает Promise<void>, что позволяет использовать его в асинхронных цепочках:

db.logs.clear().then(() => {
  console.log('Таблица очищена');
});

или с async/await:

await db.logs.clear();

Производительность и внутренние механизмы

Одним из ключевых преимуществ clear() является его производительность. В отличие от итеративного удаления:

const all = await db.logs.toArray();
for (const item of all) {
  await db.logs.delete(item.id);
}

операция clear() не выполняет:

  • выборку данных;
  • обработку индексов по каждой записи;
  • вызовы пользовательских хук-функций на уровне элементов;
  • множественные транзакционные операции.

IndexedDB реализует очистку как низкоуровневую операцию над object store, что делает её сложностью O(1) относительно количества записей.

Использование в транзакциях

Метод clear() может быть использован внутри транзакций Dexie. Это особенно важно при комплексных операциях, где требуется согласованность состояния нескольких таблиц.

await db.transaction('rw', db.users, db.logs, async () => {
  await db.users.clear();
  await db.logs.clear();
});

В этом случае очистка обеих таблиц либо завершится успешно, либо будет откатана целиком при возникновении ошибки.

Ограничения транзакционного контекста

При использовании clear() в транзакции важно учитывать следующие особенности:

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

Поведение индексов

После выполнения clear() все индексы остаются в рабочем состоянии. Это связано с тем, что IndexedDB не пересоздаёт структуру object store, а лишь удаляет все ключи и связанные значения.

Важно:

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

Ошибки и исключения

Основные ошибки, которые могут возникнуть при использовании clear():

TransactionInactiveError

Возникает при попытке выполнения операции вне активной транзакции или в завершённой транзакции.

ReadOnlyError

Появляется, если таблица не открыта в режиме записи.

await db.transaction('r', db.users, async () => {
  await db.users.clear(); // ошибка
});

ConstraintError (косвенно)

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

Влияние на хуки Dexie

Dexie поддерживает систему перехватчиков (hooks), таких как creating, updating, deleting. Однако clear() ведёт себя особым образом:

  • не вызывает deleting для каждой записи;
  • не триггерит per-item hooks;
  • может вызывать только транзакционные события уровня операции.

Это делает clear() более «грубым» инструментом, обходящим детализированную бизнес-логику, завязанную на удаление отдельных элементов.

Сравнение с альтернативными методами удаления

Удаление через delete()

await db.users.delete(id);
  • точечная операция;
  • вызывает хуки;
  • медленнее при массовом удалении.

Удаление через where().delete()

await db.users.where('active').equals(false).delete();
  • фильтрация перед удалением;
  • частичная итерация по индексу;
  • средняя производительность.

Полная очистка через clear()

await db.users.clear();
  • мгновенное удаление всех записей;
  • отсутствие итераций;
  • минимальная нагрузка на движок IndexedDB.

Поведение при больших объёмах данных

При работе с большими таблицами (десятки или сотни тысяч записей) clear() демонстрирует стабильное время выполнения, поскольку не зависит от количества элементов.

Особенности в таких сценариях:

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

Очистка нескольких таблиц

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

await db.transaction('rw', db.users, db.orders, db.logs, async () => {
  await db.users.clear();
  await db.orders.clear();
  await db.logs.clear();
});

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

Особенности отмены и отката

Если clear() выполняется внутри транзакции и происходит ошибка после её вызова, IndexedDB откатывает всю транзакцию. Это означает:

  • данные до начала транзакции сохраняются;
  • очистка не фиксируется;
  • состояние базы возвращается к исходному.
await db.transaction('rw', db.users, async () => {
  await db.users.clear();
  throw new Error('rollback');
});

В результате таблица users останется неизменной.

Практические сценарии использования

Операция clear() применяется в ситуациях, где требуется полное сбрасывание состояния:

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

Поведение при синхронизации данных

В приложениях с оффлайн-режимом clear() часто используется как часть стратегии «full sync»:

  1. очистка локальной таблицы;
  2. загрузка актуальных данных с сервера;
  3. массовая вставка новых записей.

Этот подход упрощает логику синхронизации, но требует осторожности при работе с конфликтующими локальными изменениями.

Влияние на размер базы данных

После выполнения clear() физический размер IndexedDB может не уменьшиться мгновенно, поскольку браузеры часто не освобождают пространство сразу. Однако логически таблица становится пустой, а новые записи не сталкиваются с ограничениями старых данных.

Особенности поведения в разных браузерах

Хотя спецификация IndexedDB стандартизирована, реализация очистки может иметь небольшие различия:

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

Dexie.js абстрагирует эти различия, предоставляя единый API.

Итерационные альтернативы и их недостатки

Ручное удаление записей через итерацию:

await db.users.toCollection().modify(() => {});
await db.users.where(':id').above(0).delete();

или:

for (const user of await db.users.toArray()) {
  await db.users.delete(user.id);
}

имеет существенные недостатки:

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

На этом фоне clear() остаётся наиболее эффективным инструментом полной очистки таблицы.

Особенности повторного использования таблицы

После выполнения clear() таблица остаётся полностью функциональной:

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