Событие storage и его отсутствие для IndexedDB

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

Основные функции Idb-keyval

Idb-keyval предоставляет набор простых функций:

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

Пример использования:

import { get, set, del, clear, keys } from 'idb-keyval';

await set('user', { name: 'Alice', age: 30 });
const user = await get('user'); // { name: 'Alice', age: 30 }
await del('user');
const allKeys = await keys(); // ['settings', 'theme']

Эти функции полностью асинхронные, возвращают Promise, что делает работу с ними совместимой с современными асинхронными паттернами (async/await).

Событие storage и его отличие от IndexedDB

В браузерном API localStorage существует событие storage, которое вызывается в других вкладках при изменении данных. Оно позволяет синхронизировать состояние между вкладками:

window.addEventListener('storage', (event) => {
  console.log(event.key, event.newValue);
});

Ключевой момент: для IndexedDB и, соответственно, Idb-keyval событие storage не работает. Это связано с архитектурой IndexedDB: оно изначально не предназначалось для автоматической синхронизации данных между вкладками. Каждая вкладка имеет независимую сессию IndexedDB, и изменения в одной вкладке не инициируют события в другой.

Последствия отсутствия события storage

  1. Отсутствие автоматической синхронизации: данные, сохранённые через Idb-keyval в одной вкладке, не уведомляют другие вкладки.

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

    • BroadcastChannel для отправки сообщений между вкладками.
    • Периодическое опрос данных через setInterval.
    • Использование Service Worker для глобальной коммуникации.

Пример синхронизации через BroadcastChannel:

const channel = new BroadcastChannel('idb-sync');

channel.onmess age = async (event) => {
  if (event.data.type === 'upd ate') {
    const value = await get(event.data.key);
    console.log('Обновлённые данные:', value);
  }
};

// Сохранение данных и уведомление других вкладок
await se t('user', { name: 'Bob', age: 25 });
channel.postMessage({ type: 'upd ate', key: 'user' });

Практические советы при работе с Idb-keyval

  • Использовать ключи осознанно: создавая уникальные ключи для разных сущностей, проще реализовать логику синхронизации.
  • Хранить только необходимые данные: IndexedDB может хранить большие объёмы, но частые обновления больших объектов могут быть медленными.
  • Комбинировать с другими API: для межвкладочной синхронизации всегда применять BroadcastChannel или Service Worker, так как стандартного события storage нет.
  • Асинхронная обработка ошибок: операции могут выбросить исключения (например, при переполнении квоты или закрытии базы), поэтому всегда использовать try/catch или методы Promise.catch.

Пример полного цикла с синхронизацией

import { get, se t } from 'idb-keyval';

const channel = new BroadcastChannel('idb-sync');

channel.onmess age = async (event) => {
  if (event.data.type === 'upd ate') {
    const value = await get(event.data.key);
    console.log('Синхронизированные данные:', value);
  }
};

async function updateUser(user) {
  await se t('user', user);
  channel.postMessage({ type: 'update', key: 'user' });
}

// Использование
updateUser({ name: 'Carol', age: 28 });

В этом подходе данные всегда синхронизируются между вкладками, компенсируя отсутствие события storage.

Ключевые выводы по Idb-keyval и событию storage

  • Idb-keyval упрощает работу с IndexedDB, предоставляя API в стиле ключ-значение.
  • IndexedDB не поддерживает событие storage, поэтому изменения в одной вкладке не уведомляют другие.
  • Для межвкладочной синхронизации следует использовать BroadcastChannel, Service Worker или периодический опрос.
  • Асинхронный характер операций требует использования async/await или then/catch для безопасной работы с данными.

Idb-keyval подходит для локального хранения больших объёмов данных, при этом реализация синхронизации между вкладками требует явных дополнительных инструментов.