Библиотека Idb-keyval обеспечивает удобный доступ к IndexedDB в браузере через простой API для работы с ключами и значениями. При работе с большим количеством операций чтения и записи возникает проблема накладных расходов, связанных с открытием транзакций, сериализацией данных и взаимодействием с базой данных. Батчинг (группировка) операций позволяет значительно повысить производительность, минимизируя количество транзакций и операций ввода-вывода.
Батчинг подразумевает объединение нескольких операций записи или чтения в одну транзакцию. Основные преимущества:
В Idb-keyval транзакции создаются автоматически при вызове функций
get, set, del или
update. При массовых операциях это может привести к сотням
отдельных транзакций, каждая из которых выполняется асинхронно.
Promise.all для параллельного выполненияПри необходимости записи нескольких значений можно собрать все промисы в массив и выполнить их параллельно:
import { set } from 'idb-keyval';
const data = [
{ key: 'user:1', value: { name: 'Alice' } },
{ key: 'user:2', value: { name: 'Bob' } },
{ key: 'user:3', value: { name: 'Charlie' } }
];
await Promise.all(data.map(item => set(item.key, item.value)));
Недостаток: каждая операция по-прежнему создаёт отдельную транзакцию. При небольшом количестве элементов эффект заметен, но при сотнях или тысячах записей задержка будет ощутимой.
Для снижения накладных расходов лучше использовать ручное управление транзакцией, что позволяет выполнять несколько операций в одной транзакции:
import { store } from 'idb-keyval';
import { IDBTransaction } from 'idb-keyval';
async function batchSet(entries) {
return new Promise((resolve, reject) => {
const tx = store.transaction || store._db.transaction('keyval', 'readwrite'); // доступ к IndexedDB
const objectStore = tx.objectStore('keyval');
for (const { key, value } of entries) {
const request = objectStore.put(value, key);
request.oner ror = () => reject(request.error);
}
tx.oncompl ete = () => resolve();
tx.oner ror = () => reject(tx.error);
});
}
Преимущества:
Чтение большого числа элементов также выгодно выполнять в рамках одной транзакции:
async function batchGet(keys) {
return new Promise((resolve, reject) => {
const tx = store.transaction || store._db.transaction('keyval', 'readonly');
const objectStore = tx.objectStore('keyval');
const results = {};
for (const key of keys) {
const request = objectStore.get(key);
request.onsucc ess = () => { results[key] = request.result; };
request.oner ror = () => reject(request.error);
}
tx.oncompl ete = () => resolve(results);
tx.oner ror = () => reject(tx.error);
});
}
Такой подход минимизирует накладные расходы при чтении множества ключей и обеспечивает согласованность данных.
Группировка по количеству операций Разбивать массив операций на пакеты по 50–100 элементов помогает избежать слишком больших транзакций, которые могут превышать лимиты браузера.
Объединение схожих операций Если несколько операций обновляют связанные данные, их стоит объединять в один батч для снижения числа транзакций.
Асинхронная обработка больших батчей Для очень
больших наборов данных (тысячи записей) лучше использовать
последовательное выполнение батчей с await между ними,
чтобы избежать перегрузки памяти и блокировки UI.
Кэширование в памяти Для часто используемых данных можно применять кэш в памяти, записывая их в IndexedDB только периодически, что снижает количество транзакций.
Promise.all
достаточно эффективно.Батчинг операций — ключевой приём при работе с Idb-keyval, позволяющий повысить производительность, снизить нагрузку на браузер и обеспечить атомарность изменений. Правильная организация батчей делает работу с IndexedDB более предсказуемой и экономной по ресурсам.