Web Storage : stockage des données dans le navigateur
Stockage des données locales
Web Storage est une solution adaptée aux besoins actuels de stockage de données variées, dans le navigateur. C'est aussi une technique plus puissante que les cookies, qui sont limités en taille (quelques Ko contre plusieurs Mo pour Web Storage) et qui engendrent un trafic HTTP supplémentaire pour chaque requête (que ce soit pour demander la page web, une image, une feuille de styles, un fichier javaScript, etc).
Web Storage met à disposition deux interfaces nommées sessionStorage et localStorage dont la seule différence concerne la persistance des données. Ces dernières ne sont plus véhiculées sur le réseau HTTP et elles sont facilement accessibles (lecture, modifications et suppression) pour la programmation en JavaScript.
Stockage de session sessionStorage
L'interface sessionStorage mémorise les données sur la durée d'une session de navigation, et sa portée est limitée à la fenêtre ou l'onglet actif. Lors de sa fermeture, les données sont effacées. Contrairement au cookies, il n'y a pas d'interférence. Chaque stockage de session est limité à un domaine.
Stockage local localStorage
L'interface localStorage mémorise les données sans limite de durée de vie. Contrairement à sessionStorage, elles ne sont pas effacées lors de la fermeture d'un onglet ou du navigateur. La portée de localStorage est de facto plus large : il est possible de l'exploiter à travers plusieurs onglets ouverts pour le même domaine ou plusieurs fenêtres ; à partir du moment où il s'agit bien sûr du même navigateur.
Il n'y a pas de partage des données Web Storage entre les différents navigateurs qui peuvent être installés sur une même machine.
Usages et précautions
Le stockage de données dans le navigateur web se prête à différentes applications, particulièrement lorsqu'il s'agit d'exécuter des traitements sans faire intervenir le serveur, ou lorsqu'il faut mémoriser facilement de petites quantités de données pour l'utilisateur pour les faire persister durant sa navigation. Parmi ces avantages :
stocker rapidement des données en cache sans faire intervenir le serveur (par exemple via AJAX),
augmenter la performance ressentie et faciliter les développements,
se passer des cookies et du trafic HTTP supplémentaire qu'ils représentent (un cookie est envoyé à chaque requête effectuée sur un domaine),
exploiter un espace alloué plus important que la limite imposée par les cookies (fixée à 4 Ko),
retrouver des données immédiatement à la reconnexion ou les mémoriser pour éviter la perte s'il y a déconnexion.
Attention : les données ne sont pas cryptées, accessibles facilement à tout utilisateur ayant accès au navigateur, et modifiables de la même façon. Il ne faut donc pas y placer d'informations sensibles.
Pour ces raisons et d'autres, certains navigateurs exigent de consulter la page appelant le stockage via un domaine, (c'est-à-dire avec une url en http://, que ce soit localhost ou bien un nom de domaine complet) et non pas en fichier local (adresse file://). Sinon, une exception de sécurité peut être déclenchée. Ceci peut sembler logique car les données sont en théorie attachées à un domaine.
Comment y accéder ?
Hormis les spécificités concernant la persistance des données, les méthodes d'accès sont communes :
setItem(clé,valeur) : stocke une paire clé/valeur,
getItem(clé) : retourne la valeur associée à une clé,
removeItem(clé) : supprime la paire clé/valeur en indiquant le nom de la clé,
key(index) : retourne la clé stockée à l'index spécifié,
clear() : efface toutes les paires.
Pour agrémenter le tout, la propriété .length renvoie le nombre de paires stockées.
La console Javascript des navigateurs est un outil essentiel pour tester et vérifier le bon fonctionnement de Web Storage.
Note : Les exemples suivants se basent sur sessionStorage mais fonctionneront de la même façon avec localStorage.
Stockage
sessionStorage.setItem("couleur","vert")
Le premier argument de setItem est la clé (toujours de type String). Elle précise l'endroit où sont stockées les données afin de pouvoir les y retrouver ultérieurement.
Récupération
var couleur = sessionStorage.getItem("couleur");
Grâce à la clé initialement créée avec setItem, il est possible de récupérer facilement les données. Ces dernières sont renvoyées sous la forme d'une chaîne de caractères.
Suppression
sessionStorage.removeItem("couleur");
Nous supprimons l'élément de session "couleur".
Suppression totale
sessionStorage.clear();
Suppression complète de toutes les valeurs de session.
Accès direct
Dans la plupart des situations, les variables seront accessibles directement en tant que membres de l'interface.
sessionStorage.couleur = "vert"; console.log(sessionStorage.couleur);
Examen et espace alloué
L'espace local alloué, bien que considérablement supérieur à celui disponible via un cookie est cependant limité. Personne ne tient à voir son disque dur submergé de données créées par des milliers de sites consultés. Il faut donc gérer cet espace raisonnablement avec efficacité et parcimonie. Par défaut, Internet Explorer alloue 10 Mo par espace de stockage, et les autres navigateurs (Firefox, Chrome, Opera, Safari) 5 Mo par domaine. En réalité, par mesure de sécurité, on considère l'origine de la page, c'est-à-dire que sont également distingués tous les sous-domaines, ainsi que le port ou le mode de connexion (HTTPS s'il y a lieu). Une exception QUOTA_EXCEEDED_ERR est déclenchée si le quota est atteint.
Le navigateur peut aussi très bien choisir de demander l'autorisation à l'utilisateur au préalable avant d'accueillir des données supplémentaires, et d'incrémenter la limite au fur et à mesure. C'est une option proposée par Opera, dans les paramètres webstorage qui sont accessibles à l'adresse opera:webstorage et qui offrent un contrôle fin, domaine par domaine.

Les outils de développement et diverses consoles peuvent donner accès à des vues détaillées du stockage. Par exemple sous Chrome, l'onglet Resources :

Ainsi que sous Opera Dragonfly dans l'onglet Stockage :

Internet Explorer 10 est encore un peu avare en informations, présentées au format brut, mais un outil d'exploration se retrouve facilement en entrant sessionStorage dans la console et en cliquant sur le lien proposé.

Démonstration
Une première application peut être la mémorisation de champs de formulaire, pour stocker les données entrées par l'utilisateur. Bien que ceci soit applicable à toute variable manipulée en JavaScript.
Pour ceci, l'événement change sur <textarea> est sollicité pour stocker la valeur courante de l'élément dans sessionStorage.message.
<textarea id="message" name="message" onchange="sessionStorage.message=this.value"></textarea>
Notez que cette façon de faire est très compacte mais n'est pas des plus esthétiques car le code JavaScript se retrouve "mélangé" au contenu HTML de la page. L'idéal serait de placer cette instruction dans un script externe, ou en fin de document. jQuery peut aussi être mis à contribution pour parvenir à cet objectif.
<script> // Détection du support if(typeof sessionStorage!='undefined') { if('message' in sessionStorage) { alert("Message récupéré"); document.getElementById('message').value = sessionStorage.getItem('message'); } } else { alert("sessionStorage n'est pas supporté"); } </script>
Voir la Démonstration
Un deuxième exemple très simple à mettre en place est celui d'un compteur de visites.
<p>Vous avez vu cette page <span id="visites"></span> fois</p>
Le principe est :
aller interroger la clé visites dans localStorage dès le chargement du document,
effectuer toutes les vérifications nécessaires (est-ce qu'il y a déjà quelque chose stocké à cet emplacement, peut-on convertir cette chaîne de texte en nombre entier),
incrémenter le compteur,
le stocker à nouveau au même emplacement pour le conserver,
afficher la valeur à un emplacement dans la page.
<script> // Détection if(typeof localStorage!='undefined') { // Récupération de la valeur dans web storage var nbvisites = localStorage.getItem('visites'); // Vérification de la présence du compteur if(nbvisites!=null) { // Si oui, on convertit en nombre entier la chaîne de texte qui fut stockée nbvisites = parseInt(nbvisites); } else { nbvisites = 1; } // Incrémentation nbvisites++; // Stockage à nouveau en attendant la prochaine visite... localStorage.setItem('visites',nbvisites); // Affichage dans la page document.getElementById('visites').innerHTML = nbvisites; } else { alert("localStorage n'est pas supporté"); } </script>
Pour l'affichage, cet exemple se sert de l'identifiant id et de la fonction getElementById() pour le cibler, afin d'accéder à sa propriété innerHTML, c'est-à-dire son contenu HTML interne, modifiable.
Attention : cette information restera spécifique et locale au visiteur, ne sera pas échangée avec le serveur (hors utilisation d'Ajax par exemple), et donc ne pourra être exploitée pour établir des statistiques générales.
Voir la Démonstration
Utilisation de JSON
Web Storage est bien pratique pour stocker de simples chaînes de texte. Lorsqu'il s'agit de manipuler des données plus complexes, entre autres des objets JavaScript, il faut les linéariser au préalable en chaînes de texte puisque Web Storage n'accepte que ce type de données. Le format JSON (JavaScript Object Notation) est la solution de prédilection. Deux méthodes équipent les navigateurs modernes : JSON.stringify() qui prend en paramètre un objet et renvoie une chaîne de texte linéarisée, et son inverse JSON.parse() qui reforme un objet à partir de la chaîne linéarisée. Des frameworks populaires tels que jQuery sont équipés de fonctions similaires (parseJSON) pour les anciens navigateurs qui ne seraient pas équipés en natifs de telles méthodes de conversion.
Stockage
var monobjet = { propriete1 : "valeur1", propriete2 : "valeur2" }; var monobjet_json = JSON.stringify(monobjet); sessionStorage.setItem("objet",monobjet_json);
Lecture
var monobjet_json = sessionStorage.getItem("objet"); var monobjet = JSON.parse(monobjet_json); // Affichage dans la console console.log(monobjet);
Dans le cadre de la lisibilité de cette démonstration, cet exemple de code ne fait appel que modestement à JSON, il serait possible de l'exploiter de façon beaucoup plus complexe et évoluée en fonction de la quantité de données à stocker et de leur provenance.
Voir la Démonstration
Prise en charge
Navigateur | Versions |
---|---|
Source : Alsacreations | |
Internet Explorer | 8+ |
Firefox | 3.5+ |
Chrome | 5+ |
Safari | 4+ |
Opera | 10.5+ |
Pour les versions d'Internet Explorer antérieures à IE8, il existe une interface nommée userData qui alloue 1 Mo par domaine et qui fonctionne sensiblement de la même manière. Pour l'exploiter, il faudra cependant adapter les fonctions au cas par cas, ou bien passer par un framework unifiant toutes les méthodes d'appel en fonction du stockage disponible.
Aller plus loin
L'API prévoit aussi des événements storage pour être notifié à chaque changement opéré dans l'espace alloué. Ceux-ci ne sont pas encore très répandus.
Pour mettre en place des stockages plus évolués, pour des données binaires ou bien du point de vue de la structure et des opérations de recherche, tri et maintenance, deux approches coexistent :
WebSQL dont la spécification est au point mort et qui ne sera pas maintenu à long terme ni intégré à Firefox et Internet Explorer, mais qui a été implémenté par WebKit et Opera. Cette tentative faisait entrer le langage SQL côté client, ce qui était compréhensible pour les développeurs utilisant déjà les bases côté serveur (MySQL, etc) mais n'est pas conforme à l'esprit des différents standards du web : cela nécessiterait de spécifier totalement SQL ou un sous-ensemble tel que SQLite ce qui n'est pas le rôle du W3C.
IndexedDB (Indexed Database) revêt une approche totalement orientée vers JavaScript, sans SQL, avec de la manipulation d'objets. Elle est cependant encore peu répandue (IE10 avec préfixe, Chrome et Firefox avec préfixe) ; et demande une phase d'apprentissage supplémentaire même pour les développeurs déjà aguerris avec SQL.
Article réalisé par Simon-K et dew (Alsacreations) sous licence Creative Commons