Découvrez les bonnes pratiques pour synchroniser l'état de l'application entre IndexedDB et les bibliothèques de gestion de l'état populaires.
Lorsqu'un utilisateur charge un site Web ou une application pour la première fois, la création de l'état initial de l'application utilisé pour afficher l'UI nécessite souvent un certain travail. Par exemple, l'application doit parfois authentifier l'utilisateur côté client, puis effectuer plusieurs requêtes API avant de disposer de toutes les données nécessaires à l'affichage sur la page.
Stocker l'état de l'application dans IndexedDB peut être un excellent moyen d'accélérer le temps de chargement pour les visites répétées. L'application peut ensuite se synchroniser avec n'importe quel service d'API en arrière-plan et mettre à jour l'UI avec de nouvelles données de manière paresseuse, en utilisant une stratégie obsolète pendant la validation.
Cependant, lorsque vous utilisez IndexedDB, vous devez prendre en compte de nombreux points importants qui peuvent ne pas être immédiatement évidents pour les développeurs qui débutent avec les API. Ce document répond à des questions courantes et aborde certains des points les plus importants à garder à l'esprit lors de la persistance de l'état de l'application dans IndexedDB.
Assurez la prévisibilité de votre application
Une grande partie des complexités liées à IndexedDB découlent du fait qu'il existe un grand nombre de facteurs sur lesquels vous (le développeur) n'avez aucun contrôle. Cette section explore de nombreux problèmes que vous devez garder à l'esprit lorsque vous travaillez avec IndexedDB.
Échec des écritures dans l'espace de stockage
Des erreurs d'écriture dans IndexedDB peuvent se produire pour diverses raisons. Dans certains cas, ces raisons échappent à votre contrôle en tant que développeur. Par exemple, certains navigateurs n'autorisent pas l'écriture dans IndexedDB en mode de navigation privée. Il est également possible qu'un utilisateur se trouve sur un appareil qui manque presque d'espace disque, et que le navigateur vous empêche de stocker quoi que ce soit.
C'est pourquoi il est essentiel de toujours mettre en œuvre une gestion des erreurs appropriée dans votre code IndexedDB. Cela signifie également qu'il est généralement recommandé de conserver l'état de l'application en mémoire (en plus de le stocker). Ainsi, l'interface utilisateur reste fluide lorsqu'elle s'exécute en mode navigation privée ou lorsque l'espace de stockage n'est pas disponible (même si certaines des autres fonctionnalités de l'application qui nécessitent du stockage ne fonctionnent pas).
Les données stockées peuvent avoir été modifiées ou supprimées par l'utilisateur
Contrairement aux bases de données côté serveur, dans lesquelles vous pouvez limiter les accès non autorisés, les bases de données côté client sont accessibles aux extensions de navigateur et aux outils de développement, et peuvent être effacées par l'utilisateur.
Il est rare que les utilisateurs modifient les données stockées localement, mais il est courant qu'ils les effacent. Il est important que votre application puisse gérer ces deux cas sans générer d'erreur.
Les données stockées sont peut-être obsolètes
Comme dans la section précédente, même si l'utilisateur n'a pas modifié les données lui-même, il est également possible que les données qu'il a stockées aient été écrites par une version antérieure de votre code, qui peut contenir des bugs.
IndexedDB est compatible avec les versions de schéma et la mise à niveau à l'aide de sa méthode IDBOpenDBRequest.onupgradeneeded()
. Toutefois, vous devez toujours écrire votre code de mise à niveau de manière à pouvoir gérer l'utilisateur provenant d'une version précédente (y compris une version présentant un bug).
Les tests unitaires peuvent être très utiles dans ce cas, car il est souvent impossible de tester manuellement tous les chemins et cas de mise à niveau possibles.
Préserver les performances de votre application
L'une des principales caractéristiques d'IndexedDB est son API asynchrone, mais ne vous laissez pas tromper en pensant que vous n'avez pas à vous soucier des performances lorsque vous l'utilisez. Dans certains cas, une utilisation incorrecte peut toujours bloquer le thread principal, ce qui peut entraîner un manque de réponse.
En règle générale, les lectures et les écritures dans IndexedDB ne doivent pas être plus importantes que nécessaire pour les données auxquelles on accède.
Bien qu'IndexedDB permet de stocker des objets volumineux et imbriqués sous la forme d'un seul enregistrement (ce qui est certes très pratique pour les développeurs), cette pratique doit être évitée. En effet, lorsque IndexedDB stocke un objet, il doit d'abord créer un clone structuré de cet objet, et le processus de clonage structuré se produit sur le thread principal. Plus l'objet est grand, plus le temps de blocage sera long.
Cela présente certains défis lorsque vous planifiez la persistance de l'état de l'application dans IndexedDB, car la plupart des bibliothèques de gestion d'état populaires (comme Redux) fonctionnent en gérant l'ensemble de votre arborescence d'état en tant qu'objet JavaScript unique.
Bien que la gestion de l'état de cette manière présente de nombreux avantages, et que le stockage de l'ensemble de l'arborescence d'état en tant qu'enregistrement unique dans IndexedDB puisse être tentant et pratique, le faire après chaque modification (même si le débit est limité/déboulé) entraînera un blocage inutile du thread principal, ce qui augmentera la probabilité d'erreurs d'écriture et, dans certains cas, entraînera même le plantage de l'onglet du navigateur ou son incapacité à répondre.
Au lieu de stocker l'ensemble de l'arborescence des états dans un seul enregistrement, vous devez la diviser en enregistrements individuels et ne mettre à jour que les enregistrements qui changent réellement.
Comme pour la plupart des bonnes pratiques, il ne s'agit pas d'une règle de tout ou rien. Dans les cas où il n'est pas possible de diviser un objet d'état et d'écrire simplement l'ensemble de modifications minimal, il est préférable de diviser les données en sous-arborescences et de n'écrire que celles-ci pour toujours écrire l'arborescence d'état complète. Il vaut mieux qu'il y ait peu d'améliorations.
Enfin, vous devez toujours mesurer l'impact sur les performances du code que vous écrivez. Bien qu'il soit vrai que les petites écritures sur IndexedDB sont plus performantes que les écritures volumineuses, cela n'a d'importance que si les écritures sur IndexedDB effectuées par votre application entraînent réellement de longues tâches qui bloquent le thread principal et dégradent l'expérience utilisateur. Il est important de mesurer pour comprendre ce que vous optimisez.
Conclusions
Les développeurs peuvent utiliser des mécanismes de stockage client tels que IndexedDB pour améliorer l'expérience utilisateur de leur application en conservant l'état au fil des sessions, mais aussi en réduisant le temps de chargement de l'état initial lors des visites répétées.
Bien que l'utilisation correcte d'IndexedDB puisse considérablement améliorer l'expérience utilisateur, une utilisation incorrecte ou un échec de la gestion des erreurs peut entraîner des applications défectueuses et des utilisateurs mécontents.
Étant donné que le stockage client implique de nombreux facteurs indépendants de votre contrôle, il est essentiel que votre code soit bien testé et gère correctement les erreurs, même celles qui semblent peu probables au départ.