Что такое update и зачем он нужен

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

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

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

update('counter', value => (value || 0) + 1);

В этом примере значение ключа 'counter' увеличивается на единицу. Если ключа ещё нет, используется значение по умолчанию 0. Таким образом, update объединяет проверку существования, чтение и запись в одну операцию.


Сигнатура и поведение функции

Сигнатура функции выглядит так:

update<Key, Value>(key: Key, updater: (value: Value | undefined) => Value | undefined): Promise<Value | undefined>
  • key — ключ, по которому хранится значение в IndexedDB. Может быть строкой, числом или объектом, поддерживаемым IndexedDB.
  • updater — функция, принимающая текущее значение (или undefined, если ключ отсутствует) и возвращающая новое значение. Если функция возвращает undefined, ключ будет удалён из хранилища.
  • Возвращаемое значение — промис, который резолвится новым значением после обновления или undefined, если ключ удалён.

Ключевое преимущество update в том, что она позволяет работать с состоянием как с атомарным объектом: нет риска, что два одновременных обновления перезапишут друг друга.


Примеры практического применения

1. Счётчики и агрегированные значения

update('visits', visits => (visits || 0) + 1);

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

2. Обновление объектов

update('userSettings', settings => ({
    ...settings,
    theme: 'dark'
}));

Если ключ 'userSettings' отсутствует, settings будет undefined, и оператор распространения создаст новый объект с нужным полем.

3. Удаление ключа через undefined

update('sessionToken', () => undefined);

Возвращаемое undefined приводит к удалению ключа из IndexedDB, что позволяет легко реализовать логику очистки или сброса состояния.


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

Функция update поддерживает синхронные коллбеки. Если обновление требует асинхронной логики, её следует обрабатывать внутри промисов, но сам update не поддерживает асинхронные функции напрямую. Например:

async function incrementAsyncCounter() {
    const current = await get('asyncCounter');
    await se t('asyncCounter', (current || 0) + 1);
}

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


Преимущества использования update

  1. Атомарность — чтение и запись выполняются в одной транзакции.
  2. Безопасность — предотвращает состояния гонки при множественных обновлениях.
  3. Гибкость — позволяет модифицировать существующие объекты, массивы, числа и любые поддерживаемые IndexedDB типы.
  4. Удобство удаления — возвращение undefined автоматически удаляет ключ.

Рекомендации по использованию

  • Использовать update для любых сценариев, где требуется модификация существующих данных, особенно когда ключ может быть не создан.
  • Для сложных асинхронных изменений комбинировать get и set, чтобы сохранить предсказуемость.
  • Всегда обрабатывать возможное undefined внутри функции обновления, чтобы избежать ошибок при работе с отсутствующими значениями.

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