Как использовать IndexDB для управления состоянием в JavaScript

От автора: в этой статье объясняется, как использовать IndexedDB для хранения состояния в типичном клиентском приложении JavaScript.

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

Что мы подразумеваем под «состоянием»?

Все приложения хранят состояние. Для приложения со списком задач — это список этих самых задач. Для игры — это текущий счет, доступное оружие, оставшееся время и т. д. Переменные сохраняют состояние, но они могут становиться громоздкими по мере увеличения сложности.

Системы управления состоянием, такие как Redux и Vuex, предоставляют централизованные хранилища данных. Любой компонент JavaScript может читать, обновлять или удалять данные. Некоторые системы позволяют компонентам подписываться на события изменений. Например, когда пользователь переключает светлый/темный режим, все компоненты соответственно обновляют свои стили.

Большинство систем управления состоянием хранят значения в памяти, хотя доступны методы и плагины для передачи данных в localStorage, файлы cookie и т. д.

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

Подходит ли IndexedDB для хранения состояния?

Как всегда: зависит от обстоятельств. IndexedDB предлагает некоторые преимущества:

Обычно она может хранить 1 ГБ данных, что делает ее подходящей для больших объектов, файлов, изображений и т. д. Получение этих элементов из памяти может сделать приложение более быстрым и эффективным.

В отличие от файлов cookie и веб-хранилища (localStorage и sessionStorage), IndexedDB хранит данные нативных объектов JavaScript. Нет необходимости сериализовать в JSON или снова десериализовать.

Доступ к IndexedDB является асинхронным, поэтому он оказывает минимальное влияние на основной поток обработки JavaScript.

Обратите внимание, что веб-хранилище является синхронным: ваш код JavaScript приостанавливает выполнение, пока он обращается к данным. Это может вызвать проблемы с производительностью при сохранении больших наборов данных.

Асинхронный доступ к данным имеет ряд недостатков:

API IndexedDB использует более старые методы обратного вызова и поэтому библиотека-оболочка на основе рromise является практичней.

Конструкторы класса аsync и обработчики геттеров и сеттеров для Proxy невозможны в JavaScript. Это создает некоторые проблемы для систем управления состоянием.

Создание системы управления состоянием на основе IndexedDB

В приведенном ниже примере кода реализована простая система управления состоянием в 35 строках JavaScript. Она предлагает следующие функции:

Вы можете определить состояние с помощью name(строка) и value(примитив, массив, объект и т. д.). Хранилище объектов IndexedDB сохраняет эти значения, используя имя в качестве индекса.

Любой компонент JavaScript может установить или получить значение по имени.

Когда устанавливается значение, диспетчер состояний предупреждает все подписанные компоненты об изменении. Компонент подписывается через конструктор State или путем установки или получения соответствующего значения.

Проект списка дел демонстрирует менеджер состояния. Он определяет два веб-компонента, которые обращаются к одному и тому же массиву задач todolist, управляемых объектами State:

todo-list.js: отображает todolistHTML и удаляет элемент, когда пользователь нажимает кнопку «Готово».

todo-add.js: показывает форму «добавить новый элемент», которая добавляет новые задачи в массив todolist.

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

Создание класса-оболочки IndexedDB

В статье «Начало работы» представлена оболочка IndexedDB на основе Promise. Нам нужен аналогичный класс, но он может быть проще, потому что он извлекает отдельные записи name.

Скрипт js/lib/indexeddb.js определяет класс IndexedDB с конструктором. Он принимает имя базы данных, версию и функцию обновления и возвращает созданный объект после успешного подключения к базе данных IndexedDB:

Асинхронный метод set сохраняет value с идентификатором name в хранилище объектов storeName. IndexedDB обрабатывает все операции в транзакции, которая запускает события, разрешающие или отклоняющие Promise:

Точно так же асинхронный метод get извлекает value с идентификатором name из хранилища объектов storeName:

Воспроизведение сеанса пользователя

Независимо от того, используете ли вы React, Vue или просто vanillaJS, отладка веб-приложения в рабочей среде может быть сложной и трудоемкой. OpenReplay — это альтернатива с открытым исходным кодом для FullStory, LogRocket и Hotjar. Он позволяет отслеживать и воспроизводить все, что делают ваши пользователи, и показывает, как ваше приложение ведет себя при каждой проблеме. Это похоже на то, как если бы инструмент для веб-разработчика вашего браузера был открыт, когда вы смотрите через плечо пользователя. OpenReplay — единственная доступная альтернатива с открытым исходным кодом.

Как использовать IndexDB для управления состоянием в JavaScript

Создание класса State

Сценарий js/lib/state.js импортирует IndexedDB и определяет класс State. В классе обьявляются пять статических значений свойств для экземпляров:

dbName: имя базы данных IndexedDB, используемой для хранения состояний ( «stateDB»)

dbVersion: номер версии базы данных

storeName: имя хранилища объектов, в котором хранятся все пары имя / значение ( «state»)

DB: ссылка на объект IndexedDB, используемый для доступа к базе данных

target: объект EventTarget (), который может отправлять и получать события для всех объектов State.

Конструктор принимает два необязательных параметра:

массив имен observed

функцию updateCallback. Эта функция получает name и value всякий раз, когда обновляется состояние.

Обработчик отслеживает события set, вызываемые при изменении состояния.

Класс не подключается к базе данных IndexedDB, пока это не потребуется. dbConnectМетод устанавливает соединение и использует его для всех объектов State. При первом запуске он создает новое хранилище объектов с именем state (как определено в статическом свойстве storeName):

Асинхронный метод set обновляет значение переменной name. Он добавляет name к списку observed, подключается к базе данных IndexedDB, устанавливает новое значение, и объявляет CustomEvent, которое получают все объекты State:

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

Асинхронный метод get возвращает значение name. Он добавляет name к списку observed, подключается к базе данных IndexedDB и извлекает индексированные данные:

Вы можете получать и обновлять значения состояния, используя новый объект State, например:

Другой код может получать уведомления об обновлении состояния для того же элемента, например:

Создание списка дел

Простое приложение со списком дел демонстрирует систему управления состоянием:

Как использовать IndexDB для управления состоянием в JavaScript

В файле index.html определены два элемента:

<todo-list>- список задач, управляемый ./js/components/todo-list.js, который обновляет список при добавлении и удалении задач,

<todo-add>- форма для добавления элементов в управляемый список задач ./js/components/todo-list.js.

Cценарий ./js/main.js загружает оба компонентных модуля:

Эти сценарии определяют веб-компоненты, которые получают и устанавливают общее состояние todolist. Веб-компоненты выходят за рамки данной статьи, но основные моменты:

Вы можете определить собственный HTML-элемент (например, todo-list). Имя должно содержать дефис (-), чтобы избежать конфликтов с текущими или будущими элементами HTML.

Класс JavaScript который наследуется от HTMLElement, определяет функционал. Конструктор должен вызвать super().

Браузер вызывает метод connectedCallback(), когда он готов обновить DOM. Метод может добавлять контент, при необходимости используя инкапсулированную теневую DOM, недоступную для других скриптов.

customElements.define регистрирует класс с пользовательским элементом.

Компонент todo-list

Сценарий ./js/components/todo-list.js определяет класс TodoList для компонента todo-list. Он показывает список задач и обрабатывает удаление, когда пользователь нажимает кнопку «Готово». Класс устанавливает статические строки HTML и создает новый объект State. Он отслеживает переменную todolist и запускает метод объекта render() при изменении ее значения:

Метод render() получает обновленные name и value. Он сохраняет список как свойство локального объекта, а затем добавляет HTML в Shadow DOM (созданный методом connectedCallback()):

Метод connectedCallback() сработает, когда DOM готова. Он:

создает новый Shadow DOM и передает последнее состояние todolist методу render(),

присоединяет обработчик события клика, который удаляет элемент из todolist. Метод render() будет выполняться автоматически, так как состояние изменилось.

Затем, класс TodoList регистрируется для компонента todo-list:

Компонент todo-add

Сценарий ./js/components/todo-add.js определяет класс TodoAdd для компонента. Он показывает форму, которая может добавлять новые задачи в todolist. Он устанавливает статическую строку HTML и создает новый State объект. Также он отслеживает состояние todolist и сохраняет его как свойство локального объекта:

Метод connectedCallback() cработает, когда будет готова DOM. Он:

извлекает последнее состояние todolist в локальное свойство, которое по умолчанию является пустым массивом

добавляет HTML-форму в Shadow DOM

присоединяет обработчик события, который добавляет в состояние новый элемент todolist (который, в свою очередь, обновляет todo-list компонент). Затем он очищает поле ввода, чтобы вы могли добавить еще одну задачу.

Заключение

Проекты часто избегают IndexedDB, потому что его API тяжеловесный. Это не очевидный выбор для управления состоянием, но индексированная база данных и большой объем хранилища могут сделать IndexedDB хорошим вариантом для сложных проектов, в которых хранятся значительные объемы данных.

Автор: Craig Buckler

Источник: blog.openreplay.com

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Смотреть

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии Facebook:

Комментирование закрыто.