Javascript

Stockage des données locales : Web Storage

Nous connaissions les cookies. Maintenant nous disposons de Web Storage (ou DOM Storage) pour stocker des données locales. Faisons un tour du propriétaire !

Article par (Alsacréations, Strasbourg)
Créé le , mis à jour le (169037 lectures)
Tags : javascript, Web Storage, localStorage, sessionStorage, stockage

Stockage des données dans le navigateur

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. 

Schéma de fonctionnement
Le stockage de session et le stockage local sont deux espaces distincts.

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ère.

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 efficacté 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.

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 :

Web Storage Chrome

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é.

IE10 Web Storage Console

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>

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 :

  1. aller interroger la clé visites dans localStorage dès le chargement du document
  2. 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)
  3. incrémenter le compteur
  4. le stocker à nouveau au même emplacement pour le conserver
  5. 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.

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.

Démonstration

Prise en charge

Navigateurs Versions
Internet Explorer Internet Explorer 8+
Firefox Firefox 3.5+
Chrome Chrome 5+
Safari Safari 4+
Opera 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.

Complétion et démonstrations par dew

Ressources

Commentaires

pchlj a dit le

Je connaissais pas mais c'est excellent... et merci très bonne doc ;)

Skoua a dit le

Je pensais que tout cela faisait partie du bouquet HTML5 et que donc IE8 ne le supportait pas.

Du coup, je pense que je vais bientôt m'y mettre.

Apparemment jStorage ( http://www.jstorage.info/) permet d'utiliser une même API pour localStorage et userData et fonctionne avec jQuery, Mootools et Prototype.

À tester.

rs459 a dit le

C'est un système intéressant pour faire du "prefetch", notamment en E-commerce, pour les articles "cross-selling". Ou encore pour cacher les requêtes Ajax sans pour autant envahir le BOM (si toutefois la gestion mémoire de l'espace est optimisé) et de garder la persistance des données d'une page à l'autre. Et pour les utilisateurs d'IE, ils auront une expérience utilisateur dégradée, — pas de bras pas de chocolat.

caizinho a dit le

pour le compteur de visites n' est 'il pas possible de le mettre en place pour un résultat général est non pas pour le seul utilisateur?

IncludE a dit le

@caizinho : Si tu pourrais, mais cela n'a d’intérêt que si les visiteurs sont 'identifiés' ou reconnus. En effet, tu n'auras que le nombre de visites. Ce qui n'est pas véritablement exploitable.

Pour aller dans le sens de ta pensée, on peut imaginer qu'un certain nombre d'informations relatives à l'utilisateur (geocoding/ip/info navigateur) soient récupérées, et pushées via Ajax sur le serveur qui unifiera toutes les données stokées et t'en renverra une partie pouvant te concerner... (par ex. tous les utilisateurs dans un périmètre défini ayant visité cette page, à tel moment de la journée) !