Полная сигнатура setItem

localforage.setItem(key, value, callback?)
setItem<T = any>(key: string, value: T): Promise<T>;
setItem<T = any>(key: string, value: T, callback: (err: any, value: T) => void): void;

Метод setItem является базовой операцией записи данных в localForage и используется для сохранения значения по указанному ключу в выбранное хранилище (IndexedDB, WebSQL или localStorage — в зависимости от доступности и конфигурации драйвера).


Параметры метода

key: string

Ключ, под которым сохраняется значение.

Особенности:

  • должен быть строкой;
  • используется как уникальный идентификатор записи;
  • при повторной записи по тому же ключу старое значение полностью перезаписывается;
  • чувствителен к регистру ("User" и "user" — разные ключи).

value: any

Значение, которое необходимо сохранить.

Поддерживаемые типы:

  • примитивы (string, number, boolean, null);
  • объекты и массивы;
  • вложенные структуры;
  • Date, Blob, ArrayBuffer (в зависимости от драйвера);
  • сериализуемые пользовательские структуры.

Внутренне localForage выполняет сериализацию данных (обычно через structured clone алгоритм или JSON fallback в зависимости от драйвера).

Ограничения:

  • функции не сохраняются;
  • DOM-элементы не сериализуются;
  • циклические ссылки могут приводить к ошибкам или потере данных (зависит от драйвера).

callback?: (err, value) => void

Необязательный параметр обратного вызова.

Поведение:

  • вызывается после завершения записи;
  • первым аргументом передаётся ошибка (если она возникла);
  • вторым аргументом — сохранённое значение.

Важно:

  • при использовании callback метод не возвращает Promise;
  • при отсутствии callback метод возвращает Promise.

Возвращаемое значение

Promise<T>

Promise резолвится в сохранённое значение.

Особенности:

  • возвращается именно то значение, которое было записано;
  • может отличаться от исходного объекта, если произошла сериализация/десериализация (например, потеря методов, преобразование Date).

Поведение записи

Перезапись данных

Если ключ уже существует:

localforage.setItem('token', 'abc');
localforage.setItem('token', 'def');

старое значение полностью заменяется без возможности частичного обновления.


Асинхронность

Все операции строго асинхронны независимо от драйвера:

  • IndexedDB → транзакции
  • WebSQL → SQL транзакции
  • localStorage → обёртка в async-поведение

Это гарантирует единообразное API.


Гарантии целостности

Операция записи считается атомарной на уровне драйвера:

  • либо запись завершена полностью,
  • либо не происходит изменений при ошибке.

Возможные ошибки

QuotaExceededError

  • превышен лимит хранилища браузера;
  • характерно для localStorage и некоторых конфигураций IndexedDB.

SerializationError

  • значение не может быть сериализовано;
  • встречается при циклических ссылках или неподдерживаемых типах.

InvalidArgumentsError

  • ключ не является строкой;
  • отсутствует значение.

TransactionError

  • ошибка транзакции IndexedDB/WebSQL;
  • может возникать при конкурентных операциях записи.

Поведение в разных драйверах

IndexedDB

  • наиболее стабильный вариант;
  • поддерживает большие объёмы данных;
  • работает через транзакции;
  • обеспечивает высокую производительность при больших объектах.

WebSQL

  • устаревший, но всё ещё поддерживаемый в некоторых браузерах;
  • хранение через SQL-таблицы;
  • возможны ограничения по размеру и скорости.

localStorage

  • синхронная система, но обёрнута в async API;
  • ограничения ~5–10MB;
  • хранит только строки (localForage сериализует данные).

Особенности сериализации

Перед записью данные проходят преобразование:

  • объекты → структурированное клонирование или JSON;
  • даты → строковое представление или спец-формат;
  • массивы → последовательные структуры;
  • бинарные данные → ArrayBuffer/Blob (если поддерживается драйвером).

При чтении (getItem) выполняется обратная десериализация.


Перезапись сложных объектов

await localforage.setItem('profile', {
  name: 'Alex',
  age: 30,
  preferences: {
    theme: 'dark'
  }
});

При повторной записи:

await localforage.setItem('profile', {
  name: 'Alex',
  age: 31
});

предыдущее значение не объединяется, а заменяется полностью.


Типизация и строгие сценарии

В TypeScript setItem часто используется с дженериками:

interface User {
  id: number;
  name: string;
}

await localforage.setItem<User>('user', {
  id: 1,
  name: 'John'
});

Это позволяет:

  • сохранять тип при Promise<T>;
  • уменьшать количество ошибок при чтении данных;
  • поддерживать строгую модель хранения.

Особенности конкурентных записей

При параллельных вызовах:

localforage.setItem('counter', 1);
localforage.setItem('counter', 2);

итоговое значение зависит от порядка завершения промисов, а не от порядка вызова.

Это важно учитывать при:

  • счётчиках;
  • инкрементах;
  • кэшировании состояния.

Производительность

Факторы влияния:

  • размер объекта;
  • тип драйвера;
  • количество параллельных транзакций;
  • частота записи.

IndexedDB показывает лучшую масштабируемость при:

  • больших JSON-структурах;
  • бинарных данных;
  • частых обновлениях.

localStorage становится узким местом при частых операциях записи из-за синхронной природы базового API.


Поведение при отсутствии хранилища

Если ни один драйвер недоступен:

  • операция отклоняется;
  • Promise возвращает ошибку и не выполняет запись;
  • данные не кэшируются автоматически.