idb-keyval — это лёгкая обёртка над IndexedDB,
предоставляющая удобный интерфейс для работы с ключ-значение в браузере.
Она идеально подходит для хранения данных оффлайн, включая отложенные
запросы, кэширование и временные состояния приложения. Основная цель —
упростить асинхронное взаимодействие с IndexedDB, скрывая сложность API
браузера.
Библиотека предоставляет базовые функции:
set(key, value) — сохранение значения по ключу.get(key) — получение значения по ключу.del(key) — удаление значения по ключу.clear() — очистка всего хранилища.keys() — получение массива всех ключей.Каждая из функций возвращает промис, что позволяет легко
интегрировать их с async/await.
Офлайн-очередь — это структура, которая позволяет временно сохранять
запросы, когда сеть недоступна, и выполнять их при восстановлении
соединения. Для этого используется комбинация массивов и
idb-keyval.
Пример структуры хранения:
import { set, get, del } from 'idb-keyval';
const QUEUE_KEY = 'offlineQueue';
async function enqueueRequest(request) {
const queue = (await get(QUEUE_KEY)) || [];
queue.push(request);
await set(QUEUE_KEY, queue);
}
async function dequeueRequest() {
const queue = (await get(QUEUE_KEY)) || [];
if (queue.length === 0) return null;
const request = queue.shift();
await set(QUEUE_KEY, queue);
return request;
}
Ключевые моменты:
url, method, body,
headers).set().Для обеспечения надежной работы офлайн-очереди используют несколько стратегий:
window.addEventListener('online', async () => {
let request;
while ((request = await dequeueRequest())) {
try {
await fetch(request.url, request.options);
} catch (err) {
await enqueueRequest(request); // вернуть в очередь при ошибке
break; // остановить цикл при сбое
}
}
});
Для повышения устойчивости к кратковременным сбоям сети можно реализовать повторные попытки:
async function retryRequest(request, attempt = 0) {
const MAX_ATTEMPTS = 5;
const DELAY = 1000 * Math.pow(2, attempt);
try {
await fetch(request.url, request.options);
} catch (err) {
if (attempt < MAX_ATTEMPTS) {
setTimeout(() => retryRequest(request, attempt + 1), DELAY);
} else {
await enqueueRequest(request); // вернуть в очередь
}
}
}
request преобразуются в JSON для безопасного хранения.async function safeEnqueue(request) {
if (!request || !request.url) return;
const queue = (await get(QUEUE_KEY)) || [];
queue.push(JSON.stringify(request));
await set(QUEUE_KEY, queue);
}
async function safeDequeue() {
const queue = (await get(QUEUE_KEY)) || [];
if (!queue.length) return null;
const request = JSON.parse(queue.shift());
await set(QUEUE_KEY, queue);
return request;
}
idb-keyval позволяет создавать отдельные хранилища для
разных типов данных, что полезно для разделения очередей по приоритету
или типу запроса.
import { Store, set, get } from 'idb-keyval';
const highPriorityStore = new Store('offlineDB', 'highPriorityQueue');
const lowPriorityStore = new Store('offlineDB', 'lowPriorityQueue');
await set('task1', request1, highPriorityStore);
await set('task2', request2, lowPriorityStore);
const highQueue = await get('task1', highPriorityStore);
Для мониторинга состояния офлайн-очереди полезно хранить метаданные: время добавления, количество попыток, статус.
async function enqueueWithMeta(request) {
const metaRequest = {
...request,
addedAt: Date.now(),
attempts: 0,
status: 'pending'
};
await enqueueRequest(metaRequest);
}
Преимущества:
Сочетание idb-keyval и структурированной офлайн-очереди
обеспечивает надежное хранение и повторную отправку запросов при сетевых
сбоях. Оптимизация хранения, правильная обработка ошибок и использование
метаданных делают систему устойчивой к потерям данных и легко
масштабируемой в сложных веб-приложениях.