Что можно хранить: структурированное клонирование

idb-keyval — это минималистичная библиотека для работы с IndexedDB в браузере, которая упрощает хранение и извлечение данных. Основная особенность, определяющая возможности хранения, — это использование структурированного клонирования (structured cloning). Этот механизм позволяет сохранять не только простые типы данных, но и сложные объекты, массивы, Map, Set и другие структуры, поддерживаемые браузером.

Основные поддерживаемые типы данных

Библиотека автоматически поддерживает все типы, которые могут быть структурно клонированы:

  • Примитивы: string, number, boolean, null, undefined.
  • Объекты и массивы: любые вложенные структуры объектов и массивов.
  • Map и Set: сохраняются как полноценные коллекции с ключами и значениями.
  • TypedArrays и ArrayBuffer: Uint8Array, Float32Array, DataView.
  • Date: сохраняет значение времени без потери точности.
  • RegExp: сохраняется объект регулярного выражения с его флагами и шаблоном.
  • Blob и File: объекты файлов сохраняются без преобразования.
  • ImageBitmap: в некоторых современных браузерах может быть сохранён как клонируемый объект.
  • Structured Objects: объекты, содержащие комбинации вышеуперечисленных типов, в том числе вложенные.

Что нельзя хранить напрямую

Не все объекты можно сохранить через структурированное клонирование. Ограничения связаны с особенностями браузерного API IndexedDB:

  • Функции и методы объектов: function не клонируется, будет потеряна при сохранении.
  • DOM-элементы: HTMLElement, DocumentFragment и подобные объекты нельзя хранить.
  • Символы (Symbol): не сохраняются.
  • Прототипы и классы с нестандартным поведением: при сохранении теряется цепочка прототипов.
  • Циклические ссылки: если объект содержит ссылку на сам себя, при сохранении через IndexedDB возникает ошибка.

Особенности работы с Map и Set

Map и Set в idb-keyval сохраняются в виде клонированной структуры, без потери данных. Это отличается от обычного преобразования в JSON, где Map превращается в массив массивов, а Set — в массив значений. Пример использования:

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

const userPreferences = new Map([
  ['theme', 'dark'],
  ['notifications', true]
]);

await set('prefs', userPreferences);

const prefs = await get('prefs');
console.log(prefs.get('theme')); // dark

Сохранение сложных вложенных объектов

Структурированное клонирование позволяет хранить объекты любой глубины, включая массивы объектов и вложенные структуры. Пример:

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

const sessionData = {
  user: { id: 123, name: 'Alex' },
  tokens: ['abc', 'def'],
  settings: { theme: 'light', fontSize: 14 },
  lastLogin: new Date()
};

await set('session', sessionData);

const restored = await get('session');
console.log(restored.lastLogin instanceof Date); // true

Особенность здесь в том, что Date сохраняется корректно, а вложенные объекты полностью восстанавливаются без необходимости ручного сериализатора.

Оптимизация хранения больших данных

Для больших бинарных данных (Blob, ArrayBuffer) структурированное клонирование эффективно, но иногда имеет смысл использовать дополнительные подходы:

  • Разделение больших файлов на части и хранение их по отдельным ключам.
  • Использование Blob вместо Base64-кодирования для экономии памяти.
  • Для потоков данных применять ReadableStream с последующим сохранением чанков.

Сравнение с JSON-сериализацией

В отличие от JSON.stringify, структурированное клонирование:

  • Сохраняет типы данных (Date, Map, Set) без потери информации.
  • Не требует ручного преобразования вложенных структур.
  • Работает с бинарными данными (ArrayBuffer, Blob) напрямую.
  • Не поддерживает функции и символы — отличие от JSON, где функции вообще не сериализуются, а символы игнорируются.

Ошибки при сохранении

Некорректные типы данных вызывают ошибки на этапе записи:

import { set } from 'idb-keyval';

const invalid = {
  fn: () => console.log('hi')
};

await set('invalid', invalid); // DOMException: The object could not be cloned

Для безопасного хранения необходимо заранее фильтровать неподдерживаемые типы или преобразовывать их в примитивные представления.

Итоговые рекомендации

  • Использовать структурированное клонирование для любых объектов, кроме функций и DOM-элементов.
  • Для больших коллекций или бинарных данных использовать Blob, TypedArray или разбивать данные на части.
  • Map, Set и Date можно хранить напрямую без преобразования.
  • Проверять объекты на циклические ссылки перед сохранением.

Структурированное клонирование обеспечивает гибкое и надёжное хранение практически любых данных в IndexedDB через idb-keyval, сохраняя типы и структуру без ручного сериализатора и десериализатора.