Los objetos de almacenaje web localStorage y sessionStorage permiten guardar pares de clave/valor en el navegador.
Lo que es interesante sobre ellos es que los datos sobreviven a una recarga de pgina (en el caso de sessionStorage) y hasta un reinicio completo de navegador (en el caso de localStorage). Lo veremos en breve.
Ya tenemos cookies. Por qu tener objetos adicionales?
- Al contrario que las cookies, los objetos de almacenaje web no se envan al servidor en cada peticin. Debido a esto, podemos almacenar mucha ms informacin. La mayora de los navegadores modernos permiten almacenar, como mnimo, 5 megabytes de datos y tienen opciones para configurar estos lmites.
- Tambin diferente de las cookies es que el servidor no puede manipular los objetos de almacenaje via cabeceras HTTP, todo se hace via JavaScript.
- El almacenaje est vinculado al orgen (al triplete dominio/protocolo/puerto). Esto significa que distintos protocolos o subdominios tienen distintos objetos de almacenaje, no pueden acceder a otros datos que no sean los suyos.
Ambos objetos de almacenaje proveen los mismos mtodos y propiedades:
setItem(clave, valor)almacenar un par clave/valor.getItem(clave)obtener el valor por medio de la clave.removeItem(clave)eliminar la clave y su valor.clear()borrar todo.key(ndice)obtener la clave de una posicin dada.lengthel nmero de tems almacenados.
Como puedes ver, es como una coleccin Map (setItem/getItem/removeItem), pero tambin permite el acceso a travs de index con key(index).
Vamos a ver cmo funciona.
Demo de localStorage
Las principales funcionalidades de localStorage son:
- Es compartido entre todas las pestaas y ventanas del mismo origen.
- Los datos no expiran. Persisten a los reinicios de navegador y hasta del sistema operativo.
Por ejemplo, si ejecutas ste cdigo
localStorage.setItem('test', 1);
y cierras/abres el navegador, o simplemente abres la misma pgina en otra ventana, puedes coger el tem que hemos guardado de este modo:
alert( localStorage.getItem('test') ); // 1
Solo tenemos que estar en el mismo dominio/puerto/protocolo, la url puede ser distinta.
localStorage es compartido por toda las ventanas del mismo origen, de modo que si guardamos datos en una ventana, el cambio es visible en la otra.
Acceso tipo Objeto
Tambin podemos utilizar un modo de acceder/guardar claves del mismo modo que se hace con objetos, as:
// guarda una clave
localStorage.test = 2;
// coge una clave
alert( localStorage.test ); // 2
// borra una clave
delete localStorage.test;
Esto se permite por razones histricas, y principalmente funciona, pero en general no se recomienda por dos motivos:
-
Si la clave es generada por el usuario, puede ser cualquier cosa, como
lengthotoString, u otro mtodo propio delocalStorage. En este casogetItem/setItemfuncionan correctamente, pero el acceso de simil-objeto falla;let key = 'length'; localStorage[key] = 5; // Error, no se puede asignar 'length' -
Existe un evento
storage, que se dispara cuando modificamos los datos. Este evento no se dispara si utilizamos el acceso tipo objeto. Lo veremos ms tarde en este captulo.
Iterando sobre las claves
Los mtodos proporcionan la funcionalidad get / set / remove. Pero cmo conseguimos todas las claves o valores guardados?
Desafortunadamente, los objetos de almacenaje no son iterables.
Una opcin es utilizar iteracin sobre un array:
for(let i=0; i<localStorage.length; i++) {
let key = localStorage.key(i);
alert(`${key}: ${localStorage.getItem(key)}`);
}
Otra opcin es utilizar el loop especfico para objetos for key in localStorage tal como hacemos en objetos comunes.
Esta opcin itera sobre las claves, pero tambin devuelve campos propios de localStorage que no necesitamos:
// mal intento
for(let key in localStorage) {
alert(key); // muestra getItem, setItem y otros campos que no nos interesan
}
De modo que necesitamos o bien filtrar campos des del prototipo con la validacin hasOwnProperty:
for(let key in localStorage) {
if (!localStorage.hasOwnProperty(key)) {
continue; // se salta claves como "setItem", "getItem" etc
}
alert(`${key}: ${localStorage.getItem(key)}`);
}
O simplemente acceder a las claves propias con Object.keys y iterar sobre stas si es necesario:
let keys = Object.keys(localStorage);
for(let key of keys) {
alert(`${key}: ${localStorage.getItem(key)}`);
}
Esta ltima opcin funciona, ya que Object.keys solo devuelve las claves que pertenecen al objeto, ignorando el prototipo.
Solo strings
Hay que tener en cuenta que tanto la clave como el valor deben ser strings.
Si fueran de cualquier otro tipo, como un nmero o un objeto, se convertiran a cadena de texto automticamente:
localStorage.user = {name: "John"};
alert(localStorage.user); // [object Object]
A pesar de eso, podemos utilizar JSON para almacenar objetos:
localStorage.user = JSON.stringify({name: "John"});
// en algn momento ms tarde
let user = JSON.parse( localStorage.user );
alert( user.name ); // John
Tambin es posible pasar a texto todo el objeto de almacenaje, por ejemplo para debugear:
// se ha aadido opciones de formato a JSON.stringify para que el objeto se lea mejor
alert( JSON.stringify(localStorage, null, 2) );
sessionStorage
El objeto sessionStorage se utiliza mucho menos que localStorage.
Las propiedades y mtodos son los mismos, pero es mucho ms limitado:
sessionStoragesolo existe dentro de la pestaa actual del navegador.- Otra pestaa con la misma pgina tendr un almacenaje distinto.
- Pero se comparte entre iframes en la pestaa (asumiendo que tengan el mismo orgen).
- Los datos sobreviven un refresco de pgina, pero no cerrar/abrir la pestaa.
Vamos a verlo en accin.
Ejecuta ste cdigo
sessionStorage.setItem('test', 1);
Y recarga la pgina. An puedes acceder a los datos:
alert( sessionStorage.getItem('test') ); // despus de la recarga: 1
Pero si abres la misma pgina en otra pestaa, y lo intentas de nuevo, el cdigo anterior devuelve null, que significa que no se ha encontrado nada.
Esto es exactamente porque sessionStorage no est vinculado solamente al orgen, sino tambin a la pestaa del navegador. Por sta razn sessionStorage se usa relativamente poco.
Evento storage
Cuando los datos se actualizan en localStorage o en sessionStorage, se dispara el evento storage con las propiedades:
keyla clave que ha cambiado, (nullsi se llama.clear()).oldValueel anterior valor (nullsi se aade una clave).newValueel nuevo valor (nullsi se borra una clave).urlla url del documento donde ha pasado la actualizacin.storageAreabien el objetolocalStorageosessionStorage, donde se ha producido la actualizacin.
El hecho importante es: el evento se dispara en todos los objetos window donde el almacenaje es accesible, excepto en el que lo ha causado.
Vamos a desarrollarlo.
Imagina que tienes dos ventanas con el mismo sitio en cada una, de modo que localStorage es compartido entre ellas.
Quiz quieras abrir sta pgina en dos ventanas distintas para probar el cdigo que sigue.
Si ambas ventanas estn escuchando el evento window.onstorage, cada una reaccionar a las actualizaciones que pasen en la otra.
// se dispara en actualizaciones hechas en el mismo almacenaje, desde otros documentos
window.onstorage = event => { // tambin puede usar window.addEventListener('storage', event => {
if (event.key != 'now') return;
alert(event.key + ':' + event.newValue + " at " + event.url);
};
localStorage.setItem('now', Date.now());
Hay que tener en cuenta que el evento tambin contiene: event.url la url del documento en que se actualizaron los datos.
Tambin que event.storageArea contiene el objeto de almacenaje el evento es el mismo para sessionStorage y localStorage --, de modo que storageArea referencia el que se modific. Podemos hasta querer cambiar datos en l, para responder a un cambio.
Esto permite que distintas ventanas del mismo orgen puedan intercambiar mensajes.
Los navegadores modernos tambin soportan la API de Broadcast channel API, la API especfica para la comunicacin entre ventanas del mismo orgen. Es ms completa, pero tiene menos soporte. Hay libreras que aaden polyfills para sta API basados en localStorage para que se pueda utilizar en cualquier entorno.
Resumen
Los objetos de almacenaje web localStorage y sessionStorage permiten guardar pares de clave/valor en el navegador.
- Tanto la
clavecomo elvalordeben ser strings. - El lmite es de ms de 5mb+, dependiendo del navegador.
- No expiran.
- Los datos estn vinculados al origen (dominio/puerto/protocolo).
localStorage |
sessionStorage |
|---|---|
| Compartida entre todas las pestaas y ventanas que tengan el mismo orgen | Accesible en una pestaa del navegador, incluyendo iframes del mismo origen |
| Sobrevive a reinicios del navegador | Muere al cerrar la pestaa |
API:
setItem(clave, valor)guarda pares clave/valor.getItem(clave)coge el valor de una clave.removeItem(clave)borra una clave con su valor.clear()borra todo.key(ndice)coge la clave en una posicin determinada.lengthel nmero de tems almacenados.- Utiliza
Object.keyspara conseguir todas las claves. - Puede utilizar las claves como propiedades de objetor, pero en ese caso el evento
storageno se dispara
Evento storage:
- Se dispara en las llamadas a
setItem,removeItem,clear. - Contiene todos los datos relativos a la operacin (
key/oldValue/newValue), laurldel documento y el objeto de almacenaje. - Se dispara en todos los objetos
windowque tienen acceso al almacenaje excepto el que ha generado el evento (en una pestaa en el caso desessionStorageo globalmente en el caso delocalStorage).
Comentarios
<code>, para varias lneas envolverlas en la etiqueta<pre>, para ms de 10 lneas utilice una entorno controlado (sandbox) (plnkr, jsbin, codepen)