Изоляция данных между модулями через отдельные хранилища

Библиотека Idb-keyval предоставляет лёгкий интерфейс для работы с IndexedDB в браузере, упрощая асинхронное хранение ключ-значение без необходимости писать громоздкий код с транзакциями и запросами. Одной из ключевых возможностей является создание отдельных хранилищ (stores), что позволяет изолировать данные между различными модулями приложения. Такой подход обеспечивает безопасность, предотвращает случайное перезаписывание данных и упрощает управление жизненным циклом информации в крупном приложении.

В IndexedDB каждое хранилище создаётся в рамках одной базы данных, но с уникальным именем. В Idb-keyval создание отдельного хранилища происходит через объект Store, который может быть передан в функции get, set, del и других методах библиотеки. Это позволяет каждому модулю работать с собственным namespace, не вмешиваясь в данные других модулей.

import { Store, get, set } from 'idb-keyval';

// Создание отдельного хранилища для модуля "auth"
const authStore = new Store('app-db', 'auth-module');

// Установка данных в хранилище auth
set('token', 'abc123', authStore);

// Получение данных из хранилища auth
get('token', authStore).then(value => {
    console.log(value); // 'abc123'
});

Создание и конфигурация отдельных хранилищ

Каждое хранилище в Idb-keyval создаётся с двумя параметрами:

  1. Имя базы данных (dbName) – объединяет несколько хранилищ в рамках одной IndexedDB базы.
  2. Имя хранилища (storeName) – уникальный контейнер для ключ-значение данных конкретного модуля.
const settingsStore = new Store('app-db', 'settings-module');
const cacheStore = new Store('app-db', 'cache-module');

Использование отдельных хранилищ предотвращает:

  • Коллизии ключей между модулями
  • Непреднамеренную модификацию данных сторонними модулями
  • Потенциальные ошибки при миграции данных

Основные методы работы с хранилищами

Idb-keyval предоставляет простой набор методов для CRUD-операций с учётом указанного хранилища:

  • set(key, value, store) – сохраняет значение по ключу в указанном store.
  • get(key, store) – возвращает значение по ключу.
  • del(key, store) – удаляет ключ из хранилища.
  • clear(store) – очищает всё содержимое хранилища.
  • keys(store) – возвращает массив всех ключей в хранилище.
  • upd ate(key, updater, store) – обновляет значение по ключу через функцию updater.

Пример изоляции двух модулей:

// Модуль "Профиль"
const profileStore = new Store('app-db', 'profile-module');
se t('username', 'ivan', profileStore);
set('email', 'ivan@example.com', profileStore);

// Модуль "Товары"
const productStore = new Store('app-db', 'products-module');
set('itemCount', 42, productStore);

// Проверка изоляции
get('username', productStore).then(console.log); // undefined

Использование update для безопасного изменения данных

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

import { upd ate } from 'idb-keyval';

update('itemCount', count => (count || 0) + 1, productStore)
    .then(newCount => console.log(newCount));

Совместное использование базы данных с разными хранилищами

Все модули могут находиться в одной базе данных, но при этом оставаться изолированными через разные storeName. Такой подход уменьшает нагрузку на браузер (ведь создаётся одна база данных) и обеспечивает удобство управления версионированием схемы базы:

const dbName = 'app-db';

const authStore = new Store(dbName, 'auth-module');
const settingsStore = new Store(dbName, 'settings-module');
const cacheStore = new Store(dbName, 'cache-module');

Каждое хранилище может иметь собственную стратегию очистки данных: кэш можно периодически очищать через clear(cacheStore), настройки сохраняются навсегда, токены авторизации – с ограничением по времени жизни.

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

  1. Всегда использовать отдельный store для каждого модуля.
  2. Использовать update для безопасного изменения существующих значений.
  3. Избегать прямого доступа к store других модулей.
  4. При разработке больших приложений документировать назначение каждого хранилища.
  5. При необходимости миграции данных использовать отдельные версии базы данных через изменение имени хранилища или базы.

Асинхронность и обработка ошибок

Все методы Idb-keyval возвращают Promise, поэтому необходимо обрабатывать потенциальные ошибки и использовать async/await для удобного синтаксиса:

async function saveToken(token) {
    try {
        await se t('token', token, authStore);
    } catch (err) {
        console.error('Ошибка сохранения токена:', err);
    }
}

async function loadToken() {
    try {
        const token = await get('token', authStore);
        return token;
    } catch (err) {
        console.error('Ошибка чтения токена:', err);
        return null;
    }
}

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