localStorage en HTML5. El fin de las cookies

localStorage en HTML5. El fin de las cookies

Qué es localStorage

Dentro de las múltiples novedades que existen en HTML5, una de ellas es el localStorage. Como su propio nombre indica, se trata de un espacio de almacenamiento local. A muchos les vendrá a la mente las cookies… eso que está tan de moda últimamente en los sitios web por culpa de la conocida como “ley de cookies” (se merece un artículo sólo para ella ;)).

Pues bien, cierto es que con las cookies ya podemos almacenar información en el equipo que accede a la página web… que es exactamente de lo que se trata el localStorage, pero con una serie de salvedades muy importantes.

localStorage vs Cookies

La mejor forma de entender por qué es necesario el localStorage es indicando los tres grandes problemas de las cookies:

  1. Espacio limitado: Una cookie sólo puede ocupar 4kb de espacio. Es por eso que las cookies suelen utilizarse sólo para almacenar un hash o un identificador que será utilizado por el servidor para identificar la visita.
  2. Cada vez que se realiza una petición al servidor, toda la información que está almacenada en las cookies es enviada y también es recibida nuevamente con la respuesta del servidor. O sea, en los intercambios de información entre el navegador web y el servidor siempre van pegadas las cookies.
  3. Las cookies tienen una caducidad.

Y aquí viene localStorage a solucionarlos la vida!

  1. Espacio menos limitado: localStorage puede ocupar entre 5 y 10MB dependiendo del navegador web. Con 5 o 10 megas ya podemos tener algo más de información 😉
  2. La información almacenada con localStorage no es enviada al servidor en cada petición.
  3. No existe una caducidad para localStorage, la información quedará almacenada hasta que se elimine expresamente. Aunque se cierre el navegador.

Lo sé, una cookie tiene caducidad, pero le puedes poner que caduque dentro de 5 años… vale, sí… pero caduca, con localStorage nos olvidamos de tener que guardar la cookie aumentando el tiempo de caducidad.

Sin embargo, que la información persista en el tiempo, no siempre es una buena idea. A veces lo que interesa es que la información se elimina una vez se cierre el navegador. Para estos casos, en vez de utilizar localStorage, se debe usar sessionStorage.

El sessionStorage es exactamente igual que localStorage, pero con la salvedad de que una vez cerrado el navegador se pierde la información, todo lo demás es lo mismo. Si se quiere trabajar con sessionStorage, sólo hay que coger todo el código de este articulo y donde pone localStorage cambiarlo por sessionStorage.

La API del localStorage

HTML5 incluye una API de JavaScript para interactuar con localStorage, teniendo 4 métodos disponibles para usar con nuestro localStorage.

Almacenar un valor localStorage

Para guardar la información utilizamos el método setItem:

localStorage.setItem('key', 'value');

De esta forma, en nuestro espacio de almacenamiento local, tendremos un elemento llamado key y que tendrá por valor value.

Recuperar un valor localStorage

Para recuperar la información utilizamos el método getItem:

var value = localStorage.getItem('key');

Este código Javascript almacena en la variable value el contenido almacenado para key.

Cómo saber el número de elementos almacenados en localStorage

La API asociada permite el uso de length para conocer cuantos elementos están guardados en localStorage.

alert(localStorage.length);

Al ejecutar este código, nos aparecería una alerta con el número de elementos almacenados en nuestro espacio local.

Borrar un elemento localStorage

Como es lógico, la API también permite eliminar un elemento que tengamos guardado. Para ello utilizamos el método removeItem

localStorage.removeItem('key');

Limitaciones del localStorage

Más que limitaciones, deberíamos hablar de la gran limitación: Sólo podemos almacenar cadenas de texto. O sea, no podemos guardar booleanos (true o false), no podemos guardar arrays, objetos, floats…. sólo strings.

Estamos ante una gran limitación… pero podemos superarla con unas pocas líneas de código!! ¿como? pues con ese “recurso” que cada vez cobra más fuerza: JSON.

Los navegadores que soportan localStorage (o sea, los modernos), también tienen soporte para JSON. Gracias a JSON podremos convertir un objeto (o lo que esa) en cadena de texto y almacenarlo en nuestro localStorage. Al mismo tiempo, con JSON podremos transformar la cadena recuperada de localStorage al objeto inicial 😀

// Creamos un objeto
var object = { 'uno' : '1', 'dos' : '2' };
// Lo guardamos en localStorage pasandolo a cadena con JSON
localStorage.setItem('key', JSON.stringify(object));
// Creamos una nueva variable object2 con el valor obtenido de localStorage usando JSON recuperar el objeto inicial
var object2 = JSON.parse(localStorage.getItem('key'));
// La alerta mostrará 1 por pantalla
alert(object2.uno);

Ejemplo práctico de localStorage

Ya sabemos, prácticamente, todo lo que necesitamos saber sobre localStorage, aunque no todo. Por ejemplo, existe un evento que permite “disparar” determinado código cuando un valor de localStorage es modificado, aunque por ahora no tiene mucha utilidad, por lo que he decidido ignorarlo 😉

Bien, aunque los conceptos básicos están claros, vamos a crear un pequeño script que sea un “juego” de completa la frase. OJO, muy simple y muy mejorable, pero nos sirve para el caso 😉
Descripción del juego

  • El juego consiste en la primera frase de “El Quijote de la Mancha”. En la pantalla aparecerá el texto y algunas palabras estarán substituidas por ****
  • El contenido de **** será editable, o sea, seleccionando el área con el ratón se podrá escribir y eliminar el texto de ese área.
  • Una vez esté completada la frase, se pinchará en el botón de “Comprobar”. El script comprobará si está la frase correcta o no, avisando del resultado.
  • Este script irá guardando un histórico de todos los intentos, de forma que se mostrarán, en la misma pantalla, los textos que fueron enviados a comprobación. Para almacenar estos textos utilizaremos localStorage. Una vez terminado el script, deberemos hacer varias pruebas, unas poniendo bien el texto y otras fallando.
  • Cuando tengamos el historial bastante lleno, cerraremos el navegador. Una vez cerrado lo volveremos a abrir y comprobaremos que se mantiene el historial 😀
  • También se incorporará un botón de “Reinicar” para eliminar nuestro historial.

Empecemos!!

Creando el HTML

Como vamos a escribir nuestro código atendiendo a las buenas prácticas, nuestro código HTML no tendrá nada de CSS ni de Javascript, en su lugar se incorporarán a la cabecera las llamadas a los ficheros externos dónde tendremos el código tanto CSS como Javascript.

Así pues, lo primero es crear el documento HTML (index.html) base y la cabecera del mismo:

<!DOCTYPE html>
<html>
	<head>
		<title>LocalStorage</title>
		<meta charset="utf-8" />
		<link rel="stylesheet" href="./style.css" />
    <script defer src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script defer type="text/javascript" src="./javascript.js"></script>
	</head>
	<body>
	</body>
</html>
  • Utilizamos el doctype de HTML5.
  • Tenemos nuestro title.
  • Informamos que usamos utf-8 como juego de caracteres. Recordar que el meta charset es obligatorio.
  • Cargamos el CSS gracias al tag link, indicando que es una hoja de estilos (rel stylesheet) y que el fichero a cargar es el style.css  (ubicado al mismo nivel que nuestro index.html). Aquellos que estén habituados a HTML 4.01 o XHTML notarán que no se incluyo el atributo type con valor “text/css”. Al igual que pasa con Javascript, HTML5 ya interpreta que se trata de un fichero de tipo text/css, no es preciso indicarlo.
  • Cargamos el framework jQuery desde la URL que Google nos proporciona para ello. Siempre es mejor usar la URL de Google que cargar el jQuery desde nuestro espacio web.
  • Por último, cargamos nuestro javascript… con el que “haremos la magia”.

Bueno, ya nos toca meternos en el body… así que empezaremos por ponerle una cabecera con nuestro h1

		<header>
			<h1>Uso de LocalStorage</h1>
		</header>

Empezamos con “lo divertido”. Vamos a crear la zona en la que mostraremos la frase a completar y desde la cual se podrá comprobar o reiniciar.

Está claro que se trata del contenido principal de nuestra página, por lo que todo ello estará dentro de un section. Este section tendrá un article que contendrá todo lo que acabamos de indicar:

		<section>
			<article>
				<fieldset>
					<legend>Completa la frase</legend>
					<div id="text">
						En un lugar de la <span contenteditable="true">****</span>, de cuyo nombre no quiero <span contenteditable="true">****</span>, no ha mucho tiempo que vivía un hidalgo de los de lanza en <span contenteditable="true">****</span>, adarga antigua, rocín flaco y galgo <span contenteditable="true">****</span>.
					</div>
					<button id="check">Comprobar</button>
					<button id="restart">Reiniciar</button>
				</fieldset>
			</article>
		</section>

De este código, debería llamar la atención el contenido de las etiquetas span. Cada una de las etiquetas span contiene una de las palabras que deberán ser completadas. Para permitir que se pueda escribir la palabra y eliminar los **** no vamos a utilizar “complejas” técnicas de javascript no. Vamos a utilizar el maravilloso atributo “contenteditable” de HTML5 que, como es de imaginar, permite que el contenido de esa etiqueta pueda ser editado desde el navegador. Esta es otra novedad grandiosa de HTML5, muy, pero que muy buena.

Bien, ya sólo nos falta la zona dónde listaremos el historial. Se trata de información secundaria, por lo que la colocaremos dentro de un aside:

		<aside>
			<fieldset id="history">
				<legend>Tu historial</legend>
				<article></article>
			</fieldset>
		</aside>

Vemos que tenemos la etiqueta article, pero sin contenido dentro. Es ahí dónde pondremos el contenido que se obtenga de localStorage.

Y ya tenemos todo nuestro HTML.

<!DOCTYPE html>
<html>
	<head>
		<title>LocalStorage</title>
		<meta charset="utf-8" />
		<link rel="stylesheet" href="./style.css" />
    <script defer src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script defer type="text/javascript" src="./javascript.js"></script>
	</head>
	<body>
		<header>
			<h1>Uso de LocalStorage</h1>
		</header>
		<section>
			<article>
				<fieldset>
					<legend>Completa la frase</legend>
					<div id="text">
						En un lugar de la <span contenteditable="true">****</span>, de cuyo nombre no quiero <span contenteditable="true">****</span>, no ha mucho tiempo que vivía un hidalgo de los de lanza en <span contenteditable="true">****</span>, adarga antigua, rocín flaco y galgo <span contenteditable="true">****</span>.
					</div>
					<button id="check">Comprobar</button>
					<button id="restart">Reiniciar</button>
				</fieldset>
			</article>
		</section>
		<aside>
			<fieldset id="history">
				<legend>Tu historial</legend>
				<article></article>
			</fieldset>
		</aside>
	</body>
</html>

Aplicando estilos con CSS3

* {
	font-family: monospace, serif;
	font-size: 10pt;
	line-height: 30pt;
	text-align: center;
}

button {
	border: 1px solid black;
	border-radius: 10px;
	cursor: pointer;
	margin: 20px auto;
	padding: 0 10px;
}

.correct {
	border:2px solid green;
	border-radius: 10px;
	margin: 10px;
	padding: 10px;
	text-align: left;
}

.error {
	border:2px solid red;
	border-radius: 10px;
	margin: 10px;
	padding: 10px;
	text-align: left;
}

fieldset {
	border: 1px solid black;
	border-radius: 20px;
	box-shadow: 5px 5px 5px #888;
	margin: 0 auto;
	width: 75%;
}

fieldset div {
	text-align: left;
}

legend {
	padding: 0 10px;
	text-transform: uppercase;
}

span {
	border: 1px solid blue;
	padding: 5px;
}

Este es el código CSS que he decidido utilizar para el juego, es un código muy sencillo por lo que no requiere mayores explicaciones.

¿No entiendes bien este CSS o quieres profundizar más? Aquí tienes 4 artículos del blog sobre CSS3:

Usando javascript para comprobar el texto y el almacenamiento localStorage

El código Javascript será el encargado de comprobar que el texto sea correcto, mostrar el historial por pantalla y guardarlo en almacenamiento local para que cuando se acceda de nuevo se vea todo el historial.

Como el código está comentado, lo pongo todo junto:

$(document).ready(function() {
	// Las palabras correctas por orden
	var values = [ 'Mancha', 'acordarme', 'astillero', 'corredor' ];
	
	// Recuperamos el historial almacenado en local	
	var history = JSON.parse(localStorage.getItem('history'));

	// Si no existe historial, creamos un array sin contenido
	if (history === null) {
		history = [];
	} else {
		// Como existe historial, lo recorremos para mostrar por pantalla
		// cada elemento del historial en la zona correcta del HTML.
		$.each(history, function(key, value) {
			$("#history").append(value);
		});
	}

  // Contenido que se ejecuta al clicar en "comprobar"
  $('#check').click(function() {

		var checked = 0;
		var right = 0;
		var text = '';

		// Recorremos cada span del texto para compararlo con su valor.
    $("#text span").each(function() {
			// Si la palabra es correcta, sumamos 1 a right.
			if ($(this).html() == values[checked]) {
				right += 1;
			}
			// Sumamos 1 a la variable de "spans comprobados".
			checked += 1;
		});

		if (right == checked) {
		  // Si la frase es correcta, establecemos el texto a incorporar 
			// al historial dentro de una etiqueta con class "correct"
			// para que el pintado tenga un borde verde
			text = '<div class="correct">' + $("#text").html() + '</div>';
		} else {
		  // Si la frase no es correcta, establecemos el texto a incorporar 
			// al historial dentro de una etiqueta con class "error"
			// para que el pintado tenga un borde rojo.
			text = '<div class="error">' + $("#text").html() + '</div>';
		}

		// Incorporamos el texto al array que almacenaremos en local.
		history.push(text);

		// Incorporamos el texto al historial por pantalla.
  	$("#history article").append(text);

		// Guardamos en local (localStorage) el array history
  	localStorage.setItem('history', JSON.stringify(history));
		
		if (right == checked) {
			alert('Good Job!');
		} else {
			alert('You failed!');
		}
  });

	// Contenido que se ejecuta al clicar en "reiniciar"
	$("#restart").click(function() {
		// Eliminamos el elemento "history" del almacenamiento local.
		localStorage.removeItem('history');
		// Vaciamos el historial mostrado por pantalla.
		$("#history article").html('');
	});

});

IMPORTANTE: Estamos utilizando jQuery como framework de Javascript, por lo tanto se utilizan métodos de jQuery en vez de Javascript puro, si no está familiarizado con jQuery… YA ESTÁS TARDANDO!!!

Y para finalizar, unas capturas de cómo queda nuestro juego:

Listos para empezar a jugar!

Listos para empezar a jugar!

Vaya, algo puse mal!!

Vaya, algo puse mal!!

Ahora sí!!!!

Ahora sí!!!!

Aquí tenemos el texto a validar y el historial.

Aquí tenemos el texto a validar y el historial.

Github del artículo

En mi github he creado un repositorio para el código del juego “completa la frase” utilizado en este artículo como ejemplo de uso de localStorage:

https://github.com/rolando-caldas/localStorage-completaLaFrase

Uso práctico del localStorage

Para finalizar, el localStorage tiene varios usos diferentes, aunque personalmente creo que uno destaca sobre todos los demás:

Creo firmemente que localStorage es una gran herramienta para toda la nueva generación de aplicaciones web de forma que la aplicación trabaje con datos almacenados en localStorage en vez de con datos obtenidos del servidor. La información almacenada en localStorage se tendrá que sincronizar con el servidor (ya sea de forma automática o bajo petición), pero gracias a los 5-10MB de información se pueden realizar muchas tareas que, sin localStorage, requerirían de llamadas constantes al servidor. Gracias a localStorage podemos dotar al cliente de un mayor potencial de gestión de los datos, sin depender tanto del servidor.

¿Cual es el uso práctico más interesante que se te ocurre a ti?

22 pensamientos en “localStorage en HTML5. El fin de las cookies

  1. Sinceramente, yo prefiero JavaScript a jQuery, con JS te haces menos líos, además de que me gusta poner el script en el código HTML en un . Pero eso sí, lo de localstorage, parece bastante fácil. Puede serme muy util.

    1. Félix Manuel
      Responder

      Debes de estar bromeando… ¿Con JavaScript puro te haces menos líos? ¿Qué pasa con la plaga de Internet Explorer y la compatibilidad? ¿Te gusta programar todo eso? Además, incluir TOOOOOOODO el código JavaScript en el HTML es una mala práctica.

    2. Como comenta Félix, escribir el Javascript en el HTML es una mala práctica, es algo que se debe evitar. Sobre le uso de un framework de JS o no, aunque es cuestión de gustos, utilizar un framework te ayuda con el cross-browser… si jQuery resulta muy pesado para un proyecto (por ej una app movil multiplataforma), tenemos Zepto que utiliza su misma sintáxis.

      Y por último, sobre lo del javascript dentro del código, lo dicho es una mala práctica que sólo debe llevarse a cabo cuando tu sitio web necesita una optimización máxima en cuanto a tiempo de carga, para evitarnos problemas con la apertura de un proceso externo para cargar el JS (con el bloqueo que eso conlleva), pero hablamos de casos extremos con una carga brutal de usuarios (facebook, gmail, etc), en el resto de casos se puede arreglar por otras vías más adecuadas.

      saludos!!

  2. Con las cookies se podia ver su valor fisico con el navegador. Como puedo hacer esto con el loclaStorage, es decir, donde se guardan fisicamente en el cliente.

    1. La información guardada por localStorage se almacena en el equipo, de diferente forma según el navegador utilizado. Una de las características del localStorage es que la información no se envía como parte de la cabecera HTTP, tal y como ocurre con las cookies, por lo que la info no se transmite porque sí como ocurre con las cookies.

      En firefox, se almacena la info bajo SQLite3 en el fichero webappsstore.sqlite y su ubicación depende del sistema operativo. En https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage#Storage_location_and_clearing_the_data explican dónde encontrar el fichero y cómo limpiar los datos. Además, en http://kb.mozillazine.org/Webappsstore.sqlite está la info sobre el fichero y, por último, en http://kb.mozillazine.org/Profile_folder se puede ver dónde buscar el fichero.

      En Chrome también se almacena en SQLite3 y se encuentra en ~/.config/google-chrome/Default/Local Storage (Linux) o en %LocalAppData%\Google\Chrome\User Data\Default\Local Storage (Windows). Desde las herramientas para desarrolladores (F12) en la pestaña de “Resources” se puede acceder a la info de LocalStorage y SessionStorage de la web en cuestión.

      En el caso de Opera, la información se encuentra almancenada en ficheros XML en base64. La ruta en windows es algo estilo %LocalAppData%\Opera\Opera\pstorage\

      saludos!

  3. muchas gracias hermano, busque como en 400foros y este es el unico que me respondio lo que necesita (solucionar el defecto de solo pasar String, con la herramienta JSON ) tenia todo el dia en eso! i love u! xd

  4. Gran artículo! muy bien explicado! personalmente buscaba localstorage para guardar una simple “marca” en el navegador del usuario y mostrar uno u otro mensaje diferente en función de ésta. Tipo, si ha aceptado cookies o no, esto o lo otro.
    Muchas gracias!

  5. Excelente artículo!!! Me ayudo un montón… Si tienes mas relevantes al tema te lo agradecería. Que tengas buen día!

  6. Jose Manuel Romero
    Responder

    Los datos tomados en localStorage, cuando cierro la pagina o el navegador, y vuelvo a abrirlos ¿Se quedan los datos o desaparecen?

  7. Si queremos poner una caducidad a los datos almacenados en localstorage solo basta con añadir los datos como un objeto, donde uno de ellos sea la fecha en el momento que se guarda. Despues al consultar comprobamos si la fecha es correcta.

  8. Una pregunta. Los Popups se guardan también en al carpeta de local Storage o solamente las páginas visitadas en algun Momento? Gracias

Deja un comentario