Catégories
Astuces et Design

Un aperçu des différents types de stockage de navigateur

Dans le développement back-end, le stockage est une partie commune du travail. Les données d'application sont stockées dans des bases de données, des fichiers dans le stockage d'objets, des données transitoires dans des caches… il y a des possibilités apparemment infinies pour stocker tout type de données. Mais le stockage des données ne se limite pas uniquement au back-end. Le frontal (le navigateur) est également équipé de nombreuses options pour stocker des données. Nous pouvons améliorer les performances de nos applications, enregistrer les préférences de l'utilisateur, conserver l'état de l'application sur plusieurs sessions, voire sur différents ordinateurs, en utilisant ce stockage.

Dans cet article, nous allons passer en revue les différentes possibilités pour stocker des données dans le navigateur. Nous couvrirons trois cas d'utilisation pour chaque méthode afin de saisir les avantages et les inconvénients. En fin de compte, vous serez en mesure de décider quel stockage est le mieux adapté à votre cas d'utilisation. Alors commençons!

le localStorage API

localStorage est l'une des options de stockage les plus populaires du navigateur et la solution idéale pour de nombreux développeurs. Les données sont stockées entre les sessions, jamais partagées avec le serveur et sont disponibles pour toutes les pages sous le même protocole et le même domaine. Le stockage est limité à ~ 5 Mo.

Étonnamment, l'équipe Google Chrome ne recommande pas d'utiliser cette option car elle bloque le fil de discussion principal et n'est pas accessible aux travailleurs Web et aux techniciens de service. Ils ont lancé une expérience, KV Storage, en tant que meilleure version, mais ce n'était qu'un essai qui ne semble pas encore aller nulle part.

le localStorage L'API est disponible en tant que window.localStorage et ne peut enregistrer que des chaînes UTF-16. Nous devons nous assurer de convertir les données en chaînes avant de les enregistrer dans localStorage. Les trois principales fonctions sont:

  • setItem('key', 'value')
  • getItem('key')
  • removeItem('key')

Ils sont tous synchrones, ce qui facilite leur utilisation, mais ils bloquent le thread principal.

Il vaut la peine de mentionner que localStorage a un jumeau appelé sessionStorage. La seule différence est que les données stockées dans sessionStorage ne durera que pour la session en cours, mais l'API est la même.

Voyons cela en action. Le premier exemple montre comment utiliser localStorage pour stocker les préférences de l'utilisateur. Dans notre cas, il s'agit d'une propriété booléenne qui active ou désactive le thème sombre de notre site.

Vous pouvez cocher la case et actualiser la page pour voir que l'état est enregistré dans toutes les sessions. Jetez un œil au save et load fonctions pour voir comment je convertis la valeur en chaîne et comment je l'analyse. Il est important de se rappeler que nous ne pouvons stocker que des chaînes.

Ce deuxième exemple charge les noms de Pokémon depuis la PokéAPI.

Nous envoyons une requête GET en utilisant fetch et listez tous les noms dans un ul élément. Une fois la réponse obtenue, nous la mettons en cache dans le localStorage notre prochaine visite peut donc être beaucoup plus rapide ou même fonctionner hors ligne. Nous devons utiliser JSON.stringify pour convertir les données en chaîne et JSON.parse pour le lire à partir du cache.

Dans ce dernier exemple, je montre un cas d'utilisation où l'utilisateur peut parcourir différentes pages Pokémon, et la page actuelle est enregistrée pour les prochaines visites.

Le problème avec localStorage, dans ce cas, c'est que l'état est sauvegardé localement. Ce comportement ne nous permet pas de partager la page souhaitée avec nos amis. Plus tard, nous verrons comment surmonter ce problème.

Nous utiliserons également ces trois exemples dans les prochaines options de stockage. J'ai fourché les stylos et je viens de changer les fonctions pertinentes. Le squelette général est le même pour toutes les méthodes.

L'API IndexedDB

IndexedDB est une solution de stockage moderne dans le navigateur. Il peut stocker une quantité importante de données structurées, même des fichiers et des objets blob. Comme toute base de données, IndexedDB indexe les données pour exécuter efficacement les requêtes. Il est plus complexe d’utiliser IndexedDB. Nous devons créer une base de données, des tables et utiliser des transactions.

Par rapport à localStorage , IndexedDB nécessite beaucoup plus de code. Dans les exemples, j'utilise l'API native avec un wrapper Promise, mais je recommande vivement d'utiliser des bibliothèques tierces pour vous aider. Ma recommandation est localForage car il utilise le même localStorage API mais l'implémente de manière progressive, ce qui signifie que si votre navigateur prend en charge IndexedDB, il l'utilisera; et sinon, il retombera sur localStorage.

Codons et passons à notre exemple de préférences utilisateur!

idb est le wrapper Promise que nous utilisons au lieu de travailler avec une API de bas niveau basée sur les événements. Ils sont presque identiques, alors ne vous inquiétez pas. La première chose à noter est que chaque accès à la base de données est asynchrone, ce qui signifie que nous ne bloquons pas le thread principal. Par rapport à localStorage, c'est un avantage majeur.

Nous devons ouvrir une connexion à notre base de données afin qu'elle soit disponible dans toute l'application pour la lecture et l'écriture. Nous donnons un nom à notre base de données, my-db, une version de schéma, 1, et une fonction de mise à jour pour appliquer les modifications entre les versions. Ceci est très similaire aux migrations de bases de données. Notre schéma de base de données est simple: un seul magasin d'objets, preferences. Un magasin d'objets est l'équivalent d'une table SQL. Pour écrire ou lire à partir de la base de données, nous devons utiliser des transactions. C'est la partie fastidieuse de l'utilisation d'IndexedDB. Jetez un œil à la nouvelle save et load fonctions dans la démo.

Nul doute que IndexedDB a beaucoup plus de frais généraux et que la courbe d'apprentissage est plus raide que localStorage. Pour les cas de valeur clé, il peut être plus judicieux d'utiliser localStorage ou une bibliothèque tierce qui nous aidera à être plus productifs.

Les données d'application, comme dans notre exemple Pokémon, sont le point fort d'IndexedDB. Vous pouvez stocker des centaines de mégaoctets et même plus dans cette base de données. Vous pouvez stocker tous les Pokémon dans IndexedDB et les rendre disponibles hors ligne et même indexés! C'est certainement celui à choisir pour stocker les données des applications.

J'ai ignoré la mise en œuvre du troisième exemple, car IndexedDB n'introduit aucune différence dans ce cas par rapport à localStorage. Même avec IndexedDB, l'utilisateur ne partagera toujours pas la page sélectionnée avec d'autres personnes ou ne la mettra pas en favori pour une utilisation future. Ils ne conviennent pas tous les deux à ce cas d'utilisation.

Biscuits

L'utilisation de cookies est une option de stockage unique. C’est le seul stockage également partagé avec le serveur. Les cookies sont envoyés dans le cadre de chaque demande. Cela peut être lorsque l'utilisateur parcourt les pages de notre application ou lorsque l'utilisateur envoie des demandes Ajax. Cela nous permet de créer un état partagé entre le client et le serveur, et également de partager l'état entre plusieurs applications dans différents sous-domaines. Cela n'est pas possible par les autres options de stockage décrites dans cet article. Une mise en garde: les cookies sont envoyés avec chaque demande, ce qui signifie que nous devons garder nos cookies petits pour maintenir une taille de demande décente.

L'utilisation la plus courante des cookies est l'authentification, qui n'entre pas dans le cadre de cet article. Tout comme le localStorage, les cookies ne peuvent stocker que des chaînes. Les cookies sont concaténés en une chaîne séparée par des points-virgules, et ils sont envoyés dans l'en-tête de cookie de la demande. Vous pouvez définir de nombreux attributs pour chaque cookie, tels que l'expiration, les domaines autorisés, les pages autorisées et bien d'autres.

Dans les exemples, je montre comment manipuler les cookies via le côté client, mais il est également possible de les modifier dans votre application côté serveur.

L'enregistrement des préférences de l'utilisateur dans un cookie peut être une bonne solution si le serveur peut l'utiliser d'une manière ou d'une autre. Par exemple, dans le cas d'utilisation du thème, le serveur peut fournir le fichier CSS pertinent et réduire la taille potentielle du bundle (au cas où nous ferions un rendu côté serveur). Un autre cas d'utilisation pourrait être de partager ces préférences entre plusieurs applications de sous-domaine sans base de données.

Lire et écrire des cookies avec JavaScript n'est pas aussi simple que vous pourriez le penser. Pour enregistrer un nouveau cookie, vous devez définir document.cookie – Vérifiez save fonction dans l'exemple ci-dessus. J'ai mis le dark_theme cookie et ajoutez-le un max-age attribut pour s'assurer qu'il n'expirera pas lorsque l'onglet sera fermé. Aussi, j'ajoute le SameSite et Secure les attributs. Celles-ci sont nécessaires car CodePen utilise iframe pour exécuter les exemples, mais vous n'en aurez pas besoin dans la plupart des cas. La lecture d'un cookie nécessite l'analyse de la chaîne de cookie.

Une chaîne de cookie ressemble à ceci:

key1=value1;key2=value2;key3=value3

Donc, d'abord, nous devons diviser la chaîne par un point-virgule. Maintenant, nous avons une gamme de cookies sous la forme de key1=value1, nous devons donc trouver le bon élément dans le tableau. En fin de compte, nous divisons par le signe égal et obtenons le dernier élément du nouveau tableau. Un peu fastidieux, mais une fois que vous implémentez le getCookie fonction (ou copiez-le de mon exemple: P) vous pouvez l'oublier.

Enregistrer les données d'application dans un cookie peut être une mauvaise idée! Cela augmentera considérablement la taille de la demande et réduira les performances de l'application. De plus, le serveur ne peut pas bénéficier de ces informations car il s’agit d’une version obsolète des informations qu’il contient déjà dans sa base de données. Si vous utilisez des cookies, assurez-vous de les garder petits.

L'exemple de pagination ne convient pas non plus aux cookies, tout comme localStorage et IndexedDB. La page actuelle est un état temporaire que nous aimerions partager avec d'autres, et aucune de ces méthodes n'y parvient.

Stockage d'URL

L'URL n'est pas un stockage en soi, mais c'est un excellent moyen de créer un état partageable. En pratique, cela signifie ajouter des paramètres de requête à l'URL actuelle qui peuvent être utilisés pour recréer l'état actuel. Le meilleur exemple serait les requêtes de recherche et les filtres. Si nous recherchons le terme flexbox sur CSS-Tricks, l'URL sera mise à jour en https://css-tricks.com/?s=flexbox. Voyez à quel point il est facile de partager une requête de recherche une fois que nous utilisons l'URL? Un autre avantage est que vous pouvez simplement appuyer sur le bouton d'actualisation pour obtenir de nouveaux résultats de votre requête ou même la mettre en signet.

Nous ne pouvons enregistrer que des chaînes dans l'URL, et sa longueur maximale est limitée, nous n'avons donc pas autant d'espace. Nous devrons garder notre État petit. Personne n'aime les URL longues et intimidantes.

Encore une fois, CodePen utilise iframe pour exécuter les exemples, vous ne pouvez donc pas voir l'URL changer réellement. Ne vous inquiétez pas, car tous les éléments sont là pour que vous puissiez l'utiliser où vous le souhaitez.

Nous pouvons accéder à la chaîne de requête via window.location.search et, heureusement, il peut être analysé en utilisant le URLSearchParams classe. Plus besoin d'appliquer une analyse de chaîne complexe. Lorsque nous voulons lire la valeur actuelle, nous pouvons utiliser le get une fonction. Quand on veut écrire, on peut utiliser set. Il ne suffit pas de définir uniquement la valeur; nous devons également mettre à jour l'URL. Cela peut être fait en utilisant history.pushState ou history.replaceState, selon le comportement que nous voulons accomplir.

Je ne recommanderais pas d'enregistrer les préférences d'un utilisateur dans l'URL car nous devrons ajouter cet état à chaque URL visitée par l'utilisateur, et nous ne pouvons pas le garantir. par exemple, si l'utilisateur clique sur un lien de la recherche Google.

Tout comme les cookies, nous ne pouvons pas enregistrer les données d'application dans l'URL car nous avons un espace minimal. Et même si nous avons réussi à le stocker, l'URL sera longue et n'invitera pas à cliquer. Cela pourrait ressembler à une sorte d'attaque de phishing.

Tout comme notre exemple de pagination, l'état d'application temporaire est le meilleur ajustement pour la chaîne de requête URL. Encore une fois, vous ne pouvez pas voir les modifications d'URL, mais l'URL est mise à jour avec le ?page=x paramètre de requête chaque fois que vous cliquez sur une page. Lorsque la page Web se charge, elle recherche ce paramètre de requête et récupère la bonne page en conséquence. Nous pouvons maintenant partager cette URL avec nos amis afin qu'ils puissent profiter de notre Pokémon préféré.

API de cache

L'API de cache est un stockage pour le niveau du réseau. Il est utilisé pour mettre en cache les requêtes réseau et leurs réponses. L'API Cache s'adapte parfaitement aux techniciens de service. Un technicien de service peut intercepter chaque requête réseau et, à l'aide de l'API Cache, il peut facilement mettre en cache les deux requêtes. L'agent de service peut également renvoyer un élément de cache existant en tant que réponse réseau au lieu de le récupérer à partir du serveur. Ce faisant, vous pouvez réduire les temps de chargement du réseau et faire fonctionner votre application même hors ligne. À l'origine, il a été créé pour les techniciens de service, mais dans les navigateurs modernes, l'API Cache est également disponible dans les contextes de fenêtre, d'iframe et de travail. Il s'agit d'une API très puissante qui peut améliorer considérablement l'expérience utilisateur de l'application.

Tout comme IndexedDB, le stockage de l'API Cache n'est pas limité et vous pouvez stocker des centaines de mégaoctets et même plus si vous en avez besoin. L'API est asynchrone, elle ne bloquera donc pas votre thread principal. Et il est accessible via la propriété globale caches.

Pour en savoir plus sur l'API Cache, l'équipe Google Chrome a réalisé un excellent tutoriel.

Chris a créé un stylo génial avec un exemple pratique de combinaison de techniciens de service et de l'API Cache.

Bonus: extension de navigateur

Si vous créez une extension de navigateur, vous avez une autre option pour stocker vos données. Je l'ai découvert en travaillant sur mon extension, daily.dev. Il est disponible via chrome.storage ou browser.storage, si vous utilisez le polyfill de Mozilla. Assurez-vous de demander une autorisation de stockage dans votre manifeste pour obtenir l'accès.

Il existe deux types d'options de stockage, local et synchro. Le stockage local est explicite; cela signifie qu'il n'est pas partagé et conservé localement. Le stockage de synchronisation est synchronisé dans le cadre du compte Google et partout où vous installez l'extension avec le même compte, ce stockage sera synchronisé. Fonction assez cool si vous me demandez. Les deux ont la même API, il est donc très facile de basculer entre les deux, si nécessaire. Il s'agit d'un stockage asynchrone, donc il ne bloque pas le thread principal comme localStorage. Malheureusement, je ne peux pas créer de démonstration pour cette option de stockage car elle nécessite une extension de navigateur, mais elle est assez simple à utiliser, et presque comme localStorage. Pour plus d'informations sur la mise en œuvre exacte, reportez-vous à la documentation Chrome.

Conclusion

Le navigateur dispose de nombreuses options que nous pouvons utiliser pour stocker nos données. Suivant les conseils de l'équipe Chrome, notre stockage de référence doit être IndexedDB. C'est un stockage asynchrone avec suffisamment d'espace pour stocker tout ce que nous voulons. localStorage n'est pas encouragé, mais est plus facile à utiliser que IndexedDB. Les cookies sont un excellent moyen de partager l'état du client avec le serveur, mais sont principalement utilisés pour l'authentification.

Si vous souhaitez créer des pages avec un état partageable, comme une page de recherche, utilisez la chaîne de requête de l'URL pour stocker ces informations. Enfin, si vous créez une extension, assurez-vous de lire sur chrome.storage.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *