Рекомендации по сохранению состояния приложения с помощью IndexedDB

Узнайте о лучших практиках синхронизации состояния приложения между IndexedDB и популярными библиотеками управления состоянием.

Когда пользователь впервые загружает сайт или приложение, часто требуется немало работы, чтобы создать начальное состояние приложения, которое используется для отрисовки пользовательского интерфейса. Например, иногда приложению требуется аутентифицировать пользователя на стороне клиента, а затем выполнить несколько запросов к API, чтобы получить все данные, которые нужно показать на странице.

Сохранение состояния приложения в IndexedDB может быть отличным способом ускорить время загрузки для повторных посещений. Приложение может синхронизироваться с любыми сервисами API в фоновом режиме и обновлять пользовательский интерфейс новыми данными, используя стратегию stale-while-revalidate.

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

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

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

Запись в хранилище может не работать.

Ошибки при записи в IndexedDB могут возникать по разным причинам, и в некоторых случаях эти причины находятся вне вашего контроля как разработчика. Например, некоторые браузеры не позволяют записывать данные в IndexedDB в режиме инкогнито. Также существует вероятность того, что пользователь находится на устройстве, на котором почти закончилось место на диске, и браузер ограничит вас в хранении чего-либо вообще.

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

Пользователь мог изменить или удалить сохраненные данные.

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

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

Хранящиеся данные могут быть устаревшими

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

В IndexedDB есть встроенная поддержка версий схем и обновления с помощью метода IDBOpenDBRequest.onupgradeneeded(). Однако вам все равно нужно написать код обновления так, чтобы он мог обрабатывать переход пользователя с предыдущей версии (в том числе с версии с ошибкой).

В этом случае очень полезным может быть модульное тестирование, поскольку вручную проверить все возможные пути и случаи обновления часто не представляется возможным.

Поддерживайте высокую производительность приложения

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

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

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

Это создает некоторые проблемы при планировании сохранения состояния приложения в IndexedDB, поскольку большинство популярных библиотек управления состоянием (таких как Redux) работают, управляя всем деревом состояний как одним объектом JavaScript.

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

Вместо того чтобы хранить все дерево состояний в одной записи, разбейте его на отдельные записи и обновляйте только те, которые действительно меняются.

Как и в случае с большинством рекомендаций, это не строгое правило. Если разбить объект состояния и записать только минимальный набор изменений невозможно, разбейте данные на поддеревья и записывайте только их. Это лучше, чем всегда записывать дерево состояния целиком. Небольшие улучшения лучше, чем отсутствие улучшений вообще.

Наконец, вы всегда должны измерять влияние на производительность кода, который вы пишете. Хотя небольшие записи в IndexedDB действительно будут выполняться лучше, чем большие, это имеет значение только в том случае, если записи в IndexedDB, которые делает ваше приложение, фактически приводят к длительным задачам, которые блокируют основной поток и ухудшают взаимодействие с пользователем. Важно отслеживать показатели, чтобы понимать, что вы оптимизируете.

Выводы

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

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

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