Manejar el API Storage del navegador

publicado en la categoría JavaScript
Cuando cargamos una página web, hay datos que se mantienen en la memoria y una vez que la cerramos se pierden. Guardar información localmente siempre ha sido un problema ya que para que esto fuera posible, solo se contaba con las cookies que, como se sabe gozan de muy mala reputación.

Cuando cargamos una página web, hay datos que se mantienen en la memoria y, una vez que la cerramos se pierden. Guardar información localmente (en el dispositivo del usuario) siempre ha sido un problema ya que para que esto fuera posible, solo se contaba con las cookies a los que podía accederse desde el mismo dominio que las había creado pero, como sólo son textos con una longitud máxima muy pequeña, su uso está muy limitado y para colmo, las cookies gozan de mala reputación.

Los navegadores modernos han resuelto esto de manera simple, utilizando un objeto llamado localStorage con el que es posible usar JavaScript para guardar y leer datos desde cualquier dispositivo, sin generar problemas de seguridad.

El objeto localStorage tiene es muy sencillo de manejar ya que sólo tiene unos pocos métodos a los cuales podemos acceder.

Para guardar algo usamos setItem() que requiere dos parámetros, un nombre cualquiera que lo identifique y el valor a guardar. Hay dos sintaxis posibles; por ejemplo:

localStorage.setItem("ejemplo","un dato cualquiera");
//  o bien:
localStorage["ejemplo"] ="un dato cualquiera";

Una vez guardado, podríamos cerrar el navegador, apagar el dispositivo, volver otro día a esa página y leer ese dato cuando lo deseemos. Esa es otra de las ventajas de este sistema; las cookies deben ser leídas siempre cada vez que se carga la página, en cambio, estos datos son mucho más flexibles porque podemos leerlos cuando lo necesitemos.

Para leerlo usamos el método getItem() con el nombre de la clave (key) que le habíamos dado previamente:

var eldato = localStorage.getItem("ejemplo"); // leemos el dato
// y ahora podemos usarlo como cualquier otro
alert(eldato); // la ventana nos mostrará el texto

Si queremos eliminarlo, usamos el método removeItem() con el nombre de la clave:

localStorage.removeItem("ejemplo"));

Como localStorage es un objeto, usando length podemos saber cuántas claves hemos guardado y usando key() podemos leerlas una por una utilizando su índice:

for (var i=0;i<localStorage.length;i++) {
	alert(localStorage.key(i));
}

Para eliminar todas las claves usamos el método clear():

localStorage.clear();

Claro que la vida nunca es tan simple; todo esto tiene una limitación, si lo que guardamos son textos (strings), no hay problema pero, otro tipo de datos requieren que se los maneje con cierto cuidado. Por ejemplo, algo bastante común es utilizar arrays para establecer datos múltiples y para guardarlas primero debemos convertirlas con JSON.stringify() y para leerlas, volverlas a convertir con JSON.parse():

// manejando un array de datos
var arr = ["uno","dos","tres","cuatro"];
localStorage.setItem( "ejemplo1", JSON.stringify(arr) ); // lo guardamos
var miarray = JSON.parse(localStorage.getItem("ejemplo1")); // lo leemos

// lo mismo ocurriría si quisiéramos manejar objetos:
var obj = { nombre : "Fulano", id: "1234567", n : 10 };
localStorage.setItem( "ejemplo2", JSON.stringify(obj) );
var miobjeto = JSON.parse(localStorage.getItem("ejemplo2"));

Si vamos a hacer un uso intensivo de localStorage, lo mejor es tener alguna función que haga que la tarea de codificar sea más simple.

En este caso la llamaremos localCACHE y tendrá tres parámetros:
accion indicará el método que queremos usar
save guarda un dato detipo texto
load carga un dato
del elimina un dato
tojson guarda un dato de tipo array u object
parse carga un dato tipo json
key indicará el nombre de la clave sobre la que queremos operar
data es opcional y serán los datos a guardar cuando sea necesario

Si hubo algún error devuelve false. Por el contrario, si todo está bien, devuelve true o el dato leído.

function localCACHE(accion,key,data){
	var CACHE = window["localStorage"];
	try {
		switch(accion){
			case "save":
				CACHE.setItem(key,data);
				return true;
				break;
			case "load":
				// devuelve el dato leído o null si no existe
				return CACHE.getItem(key);
				break;
			case "del":
				CACHE.removeItem(key);
				return true;
				break;
			case "tojson":
				CACHE.setItem(key,JSON.stringify(data));
				return true;
				break;
			case "parse":
				var temp = CACHE.getItem(key);
				/*
					en caso e problemas podemos usar esta alternativa:
					var temp = CACHE.getItem(key).split(",");
				*/
				return JSON.parse(temp); // devuelve el array u objeto
				break;
		}
	} catch(e){
		return false; // ante cualquier otro error devuelve false
	}
}

ver en GitHub

Ejemplos de uso:

// guardamos un dato en la clave llamada "ejemplo"
localCACHE("save", "ejemplo", dato);

// guardamos un array en la clave llamada "ejemplo"
localCACHE("tojson", "ejemplo", dato);

// leemos los datos guardados en la clave llamada "ejemplo"
var datos = localCACHE("load", "ejemplo");

// leemos el array guardada en la clave llamada "ejemplo"
var datos = localCACHE("parse", "ejemplo");

Otro ejemplo con algo básico; verificamos que una clave exista, si es así, la usamos, en caso contrario, la creamos y guardamos localmente:

var elusuario = localCACHE("load", "nombre_usuario"); // leemos la cache buscando la clave
if (elusuario===null){
	// no existe así que la creamos
	elusuario = "nuevo nombre";
	localCACHE("save", "nombre_usuario", elusuario); // y lo guardamos
} else {
	// existe así que usamos el dato
}
alert(elusuario);

La propiedad localStorage tiene una variante llamada sessionStorage que posee los mismos métodos pero se diferencia en que los datos almacenados son borrados cuando finaliza la sesión del navegador, es decir, sólo son accesibles en la ventana o pestaña donde fueron creados.

Por supuesto, el espacio disponible para estos datos es limitado y dependen de cada navegador y dispositivo; si se trata de PCs de escritorio, varía entre 5 y 10MB; en móviles entre 2 y 10MB pero no hay datos muy claros al respecto. Aunque a simple vista puede parecer poco en estas épocas de gigas y teras, en realidad es más que suficiente para cualquier uso normal.

¿Y a que llamamos uso normal? ¿Para que pude usarse esto? No sólo para guardar datos sueltos, también puede guardarse HTML y funcionar como caché, archivos de fonts personales o cualquier cosa que alivie la carga desde el servidor; mejorando sustancialmente la velocidad de las páginas.