Prácticas recomendadas para conservar el estado de la aplicación con IndexedDB

Conoce las prácticas recomendadas para sincronizar el estado de la aplicación entre IndexedDB y bibliotecas populares de administración de estado.

Cuando un usuario carga un sitio web o una aplicación por primera vez, a menudo se requiere una gran cantidad de trabajo para construir el estado inicial de la aplicación que se usa para renderizar la IU. Por ejemplo, a veces, la app necesita autenticar al usuario del cliente y, luego, realizar varias solicitudes a la API antes de tener todos los datos que necesita mostrar en la página.

Almacenar el estado de la aplicación en IndexedDB puede ser una excelente manera de acelerar el tiempo de carga de las visitas repetidas. Luego, la app puede sincronizarse con cualquier servicio de API en segundo plano y actualizar la IU con datos nuevos de forma diferida, empleando una estrategia de revalidación mientras está inactiva.

Sin embargo, cuando se usa IndexedDB, hay muchos aspectos importantes que tener en cuenta que pueden no ser evidentes de inmediato para los desarrolladores que son nuevos en las APIs. En este documento, se responden preguntas frecuentes y se analizan algunos de los aspectos más importantes que debes tener en cuenta cuando persistes el estado de la aplicación en IndexedDB.

Mantén tu app predecible

Muchas de las complejidades de IndexedDB se deben al hecho de que hay muchos factores sobre los que tú (el desarrollador) no tienes control. En esta sección, se exploran muchos de los problemas que debes tener en cuenta cuando trabajas con IndexedDB.

Es posible que las operaciones de escritura en el almacenamiento fallen.

Los errores de escritura en IndexedDB pueden deberse a varios motivos y, en algunos casos, estos motivos están fuera de tu control como desarrollador. Por ejemplo, algunos navegadores no permiten escribir en IndexedDB cuando se usa el modo de navegación privada. También es posible que un usuario esté en un dispositivo que casi no tiene espacio en el disco, y el navegador no te permitirá almacenar nada.

Por este motivo, es fundamental que siempre implementes una administración de errores adecuada en tu código de IndexedDB. Esto también significa que, por lo general, es una buena idea mantener el estado de la aplicación en la memoria (además de almacenarlo) para que la IU no falle cuando se ejecuta en modo de navegación privada o cuando no hay espacio de almacenamiento disponible (incluso si algunas de las otras funciones de la app que requieren almacenamiento no funcionan).

Es posible que el usuario haya modificado o borrado los datos almacenados.

A diferencia de las bases de datos del servidor, en las que puedes restringir el acceso no autorizado, las extensiones del navegador y las herramientas para desarrolladores pueden acceder a las bases de datos del cliente, y el usuario puede borrarlas.

Si bien es poco común que los usuarios modifiquen sus datos almacenados de forma local, es bastante común que los borren. Es importante que tu aplicación pueda controlar ambos casos sin errores.

Es posible que los datos almacenados estén desactualizados

Al igual que en la sección anterior, incluso si el usuario no modificó los datos, también es posible que los datos que tiene en el almacenamiento los haya escrito una versión anterior de tu código, posiblemente una versión con errores.

IndexedDB tiene compatibilidad integrada con las versiones de esquemas y la actualización con su método IDBOpenDBRequest.onupgradeneeded(). Sin embargo, debes escribir el código de actualización de manera que pueda controlar al usuario que proviene de una versión anterior (incluida una versión con un error).

Las pruebas de unidades pueden ser muy útiles aquí, ya que a menudo no es factible probar manualmente todas las posibles rutas de actualización y casos.

Mantén el rendimiento de tu app

Una de las funciones clave de IndexedDB es su API asíncrona, pero no dejes que eso te engañe y pienses que no necesitas preocuparte por el rendimiento cuando la usas. Existen varios casos en los que el uso inadecuado puede bloquear el subproceso principal, lo que puede provocar que no responda.

Como regla general, las operaciones de lectura y escritura en IndexedDB no deben ser más grandes que las necesarias para los datos a los que se accede.

Si bien IndexedDB permite almacenar objetos grandes anidados como un solo registro (y hacerlo es bastante conveniente desde la perspectiva de un desarrollador), se debe evitar esta práctica. El motivo es que, cuando IndexedDB almacena un objeto, primero debe crear un clon estructurado de ese objeto, y el proceso de clonación estructurado se produce en el subproceso principal. Cuanto más grande sea el objeto, más largo será el tiempo de bloqueo.

Esto presenta algunos desafíos cuando se planifica cómo conservar el estado de la aplicación en IndexedDB, ya que la mayoría de las bibliotecas populares de administración de estados (como Redux) funcionan administrando todo el árbol de estados como un solo objeto JavaScript.

Si bien administrar el estado de esta manera tiene muchos beneficios y almacenar todo el árbol de estado como un solo registro en IndexedDB puede ser tentador y conveniente, hacerlo después de cada cambio (incluso si se reduce la velocidad o se anula el rebote) provocará un bloqueo innecesario del subproceso principal, aumentará la probabilidad de errores de escritura y, en algunos casos, incluso hará que la pestaña del navegador falle o deje de responder.

En lugar de almacenar todo el árbol de estados en un solo registro, debes dividirlo en registros individuales y solo actualizar los registros que realmente cambian.

Al igual que con la mayoría de las prácticas recomendadas, esta no es una regla de todo o nada. En los casos en los que no es posible dividir un objeto de estado y solo escribir el conjunto de cambios mínimo, es preferible dividir los datos en subárboles y solo escribirlos en lugar de escribir siempre todo el árbol de estado. Las pequeñas mejoras son mejores que no hacer ninguna.

Por último, siempre debes medir el impacto en el rendimiento del código que escribas. Si bien es cierto que las operaciones de escritura pequeñas en IndexedDB tendrán un mejor rendimiento que las operaciones de escritura grandes, esto solo importa si las operaciones de escritura en IndexedDB que realiza tu aplicación realmente generan tareas largas que bloquean el subproceso principal y degradan la experiencia del usuario. Es importante realizar mediciones para comprender para qué estás realizando la optimización.

Conclusiones

Los desarrolladores pueden usar mecanismos de almacenamiento de clientes, como IndexedDB, para mejorar la experiencia del usuario de su aplicación, no solo conservando el estado en todas las sesiones, sino también disminuyendo el tiempo que se tarda en cargar el estado inicial en las visitas repetidas.

Si bien usar IndexedDB de forma correcta puede mejorar significativamente la experiencia del usuario, usarlo de forma incorrecta o no controlar los casos de error puede provocar que las apps fallen y que los usuarios no estén conformes.

Dado que el almacenamiento del cliente implica muchos factores fuera de tu control, es fundamental que tu código esté bien probado y controle correctamente los errores, incluso aquellos que, en un principio, pueden parecer poco probables.