0% encontró este documento útil (0 votos)
161 vistas14 páginas

Almacenamiento Local HTML5

El documento habla sobre el almacenamiento local en HTML5. Ofrece tres tecnologías: Web Storage, Web SQL Database e IndexedDB. Web Storage es el más simple y almacena datos en parejas clave-valor. Web SQL Database es un sistema de almacenamiento basado en SQL, aunque ya no se mantendrá en el futuro. IndexedDB es un sistema de almacenamiento basado en objetos.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
161 vistas14 páginas

Almacenamiento Local HTML5

El documento habla sobre el almacenamiento local en HTML5. Ofrece tres tecnologías: Web Storage, Web SQL Database e IndexedDB. Web Storage es el más simple y almacena datos en parejas clave-valor. Web SQL Database es un sistema de almacenamiento basado en SQL, aunque ya no se mantendrá en el futuro. IndexedDB es un sistema de almacenamiento basado en objetos.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

HTML5 ← Anterior Siguiente →

CAPÍTULO 8 ALMACENAMIENTO LOCAL


El almacenamiento de datos es fundamental en cualquier aplicación web o de escritorio. Hasta
ahora, el almacenamiento de datos en la web se realizaba en el servidor, y era necesario algún
tipo de conexión con el cliente para trabajar con estos datos. Con HTML5 disponemos de tres
tecnologías que permiten que las aplicaciones almacenen datos en los dispositivos cliente.
Según las necesidades de la aplicación, la información puede sincronizarse también con el
servidor o permanecer siempre en el cliente. Estas son las posibilidades que tenemos:

• Web Storage: [Link] Es el sistema de almacenamiento


más simple, ya que los datos se almacenan en parejas de clave/valor. Ampliamente
soportado por todos los navegadores.
• Web SQL Database: [Link] Sistema de almacenamiento
basado en SQL. La especificación indica que no va a ser mantenido en el futuro, pero
actualmente su uso está muy extendido y es soportado por Chrome, Safari y Opera.
• IndexedDB: [Link] Sistema de almacenamiento basado en
objetos. Actualmente soportado por Chrome, Firefox e Internet Explorer.

8.1 WEB STORAGE


Este API de almacenamiento ofrece dos posibilidades para guardar datos en el navegador:
sessionStorage y localStorage . El primero mantiene los datos durante la sesión actual
(mientras la ventana o pestaña se mantenga abierta), mientras que el segundo almacena los
datos hasta que sean eliminados explícitamente por la aplicación o el usuario. Ambos modos
de almacenamiento se encuentran relacionados con el dominio que los ha creado.

• sessionStorage : objeto global que mantiene un área de almacenamiento disponible a


lo largo de la duración de la sesión de la ventana o pestaña. La sesión persiste mientras
que la ventana permanezca abierta y sobrevive a recargas de página. Si se abre una
nueva página en una pestaña o ventana, una nueva sesión es inicializada, por lo que no
es posible acceder a los datos de otra sesión.

• localStorage : el almacenamiento local por su parte, funciona de la misma forma que


el almacenamiento de sesión, con la excepción de que son capaces de almacenar los
datos por dominio y persistir más allá de la sesión actual, aunque el navegador se cierre
o el dispositivo se reinicie.

Nota

Cuando hacemos referencia la ventana o pestaña, nos estamos refiriendo al objeto


window . Una nueva ventana abierta utilizando el método [Link]() , pertenece a
la misma sesión.
Tanto sessionStorage como localStorage forman parte del Web Storage, por lo que
comparten el mismo API:

readonly attribute unsigned long length;


getter DOMString key(in unsigned long index);
getter DOMString getItem(in DOMString key);
setter creator void setItem(in DOMString key, in any data);
deleter void removeItem(in DOMString key);
void clear();

Este API hace que sea muy sencillo acceder a los datos. El método setItem almacena el valor,
y el método getItem lo obtiene, como se muestra a continuación:

[Link]('twitter', '@starkyhach');
alert( [Link]('twitter') ); // muestra @starkyhach

Es importante darse cuenta, que tal y como se indica en el API, el método getItem siempre
devuelve un String, por lo que si intentamos almacenar un objeto, el valor devuelto será
"[Object object]". El mismo problema ocurre con los número, por lo que es importante tenerlo
en cuenta para evitar posibles errores. Por ejemplo:

[Link]('total', 120);
function calcularCosteEnvio(envio) {
return [Link]('total') + envio;
}

alert(calcularCosteEnvio(25));

En este caso, esperamos que el coste total (120) se almacene como número, y al añadir el
coste del envío, el resultado sea 145. Pero como sessionStorage devuelve un String, el
resultado no es el esperado sino 12025.

8.1.1 ELIMINANDO DATOS


Disponemos de tres formas de eliminar datos del almacenamiento local: utilizando delete ,
removeItem y clear . El método removeItem toma como parámetro el nombre de la clave a
eliminar (el mismo que utilizamos en getItem y setItem ), para eliminar un ítem en
particular. Por su parte, el método clear , elimina todas las entradas del objeto.

[Link]('twitter', '@starkyhach');
[Link]('flickr', '[Link]');
alert( [Link] ); // Muestra 2
[Link]('twitter');
alert( [Link] ); // Muestra 1
[Link]();
alert( [Link] ); // Muestra 0

8.1.2 ALMACENANDO ALGO MÁS QUE STRINGS


Una manera de almacenar objetos es utilizando JSON. Como la representación de los objetos
en JSON puede realizarse a través de texto, podemos almacenar estas cadenas de texto y
recuperarlas posteriormente para convertirlas en objetos.

var videoDetails = {
title : 'Matrix',
author : ['Andy Wachowski', 'Larry Wachowski'],
description : 'Wake up Neo, the Matrix has you...',
rating: '-2'
};

[Link]('videoDetails', [Link](videoDetails) );
var videoDetails = [Link]([Link]('videoDetails');

8.1.3 EVENTOS DE ALMACENAMIENTO


Una de las funcionalidades más interesantes de Web Storage es que incluye una serie de
eventos que nos indican cuándo se ha producido un cambio en los datos almacenados. Estos
eventos no se lanzan en la ventana actual donde se han producido los cambios, sino en el
resto de ventadas donde los datos pueden verse afectados.

Esto quiere decir que los eventos para sessionStorage son lanzados en los iframe dentro
de la misma página, o en las ventanas abiertas con [Link]() . Para localStorage ,
todas las ventanas abiertas con el mismo origen (protocolo + host + puerto) reciben los
eventos.

Cuando se lanzan los eventos, éstos contienen toda la información asociada con el cambio de
datos:

StorageEvent {
readonly DOMString key;
readonly any oldValue;
readonly any newValue;
readonly DOMString url;
readonly Storage storageArea;
};

storageArea hace referencia al objeto sessionStorage o localStorage . Estos eventos se


lanzan dentro del objeto window :

function handleStorage(event) {
event = event || [Link]; // support IE8
if ([Link] === null) { // it was removed
// Do somthing
} else {
// Do somthing else
}
}

[Link]('storage', handleStorage, false);


[Link]('storage', handleStorage);

Ejercicio 8

Ver enunciado

8.2 WEB SQL


Web SQL es otra manera de almacenar y acceder a datos en el dispositivo. Realmente, no
forma parte de la especificación de HTML5, pero es ampliamente utilizado para el desarrollo
de aplicaciones web. Como su nombre indica, es una base de datos basada en SQL, más
concretamente en SQLite. La utilización del API se resume en tres simples métodos:

• openDatabase : abrir (o crear y abrir) una base de datos en el navegador del cliente.

• transaction : iniciar una transacción.

• executeSql : ejecutar una sentencia SQL.

Como en la mayoría de librearías de JavaScript, el API de Web SQL realiza llamadas diferidas a
funciones, una vez completadas las operaciones.

[Link](sql, [], function () {


// my executed code lives here
});

Debido a la naturaleza de estas llamadas, significa que el API de Web SQL es asíncrono, por lo
que es necesario tener cuidado con el orden en el que se ejecutan las sentencias SQL. Sin
embargo, las sentencias SQL se encolan y son ejecutadas en orden, por lo que podemos estar
tranquilos en ese sentido: podemos crear tablas y tener la seguridad que van a ser creadas
antes de acceder a los datos.

8.2.1 CREANDO Y ABRIENDO LA BD


El uso clásico de la API implica abrir (o crear) la base de datos y ejecutar algunas sentencias
SQL. Al abrir la base de datos por primera vez, ésta es creada automáticamente. Es necesario
especificar el número de versión de base de datos con el que se desea trabajar, y si no
especificamos correctamente éste número de versión, es posible que provoquemos un error
del tipo INVALID_STATE_ERROR .
var db = openDatabase('mydb', '1.0', 'My first database', 2 * 1024 * 102
4);

La última versión de la especificación incluye un quinto argumento en la función


openDatabase , pero no es soportado por muchos navegadores. Los valores que pasamos a
esta función son los siguientes:

1. El nombre de la base de datos.

2. El número de versión de base de datos con el que deseamos trabajar.

3. Un texto descriptivo de la base de datos.

4. Tamaño estimado de la base de datos, en bytes .

El valor de retorno de esta función es un objeto que dispone de un método transaction , a


través del cual vamos a ejecutar las sentencias SQL.

8.2.2 TRANSACCIONES
Ahora que tenemos la base de datos abierta, podemos crear transacciones para ejecutar
nuestras sentencias SQL. La idea de utilizar transacciones, en lugar de ejecutar las sentencias
directamente, es la posibilidad de realizar rollback. Esto quiere decir, que si la transacción falla
por algún motivo, se vuelve al estado inicial, como si nada hubiese pasado.

[Link](function (tx) {
[Link]('DROP TABLE foo');

// known to fail - so should rollback the DROP statement


[Link]('INSERT INTO foo (id, text) VALUES (1, "foobar")');
}, function (err) {
alert([Link]);
});

Una vez listo el objeto transacción ( tx en el ejemplo), podemos ejecutar sentencias SQL.

8.2.3 EJECUTAR SENTENCIAS SQL


El método executeSql es utilizado tanto para sentencias de escritura como de lectura.
Incluye protección contra ataques de inyección SQL y proporciona llamadas a métodos
(callback) para procesar los resultados devueltos por una consulta SQL.

Su sintaxis es la siguiente:

[Link](function (tx) {
[Link](sqlStatement, arguments, callback, errorCallback);
});
Donde:

1. sqlStatement : indica la sentencia SQL a ejecutar. Como hemos dicho, puede ser
cualquier tipo de sentencia; creación de tabla, insertar un registro, realizar una consulta,
etc.

2. arguments : corresponde con un array de argumentos que pasamos a la sentencia SQL.


Es recomendable pasar los argumentos a la sentencia de esta manera, ya que el propio
método se ocupa de prevenir inyecciones SQL.

3. callback : función a ejecutar cuando la transacción se ha realizado de manera correcta.


Toma como parámetros la propia transacción y el resultado de la transacción.

4. erroCallback : función a ejecutar cuando la transacción se ha producido un error en la


sentencia SQL. Toma como parámetros la propia transacción y el error producido.

Un ejemplo de selección de registros sería el siguiente:

[Link](function (tx) {
[Link]('SELECT * FROM foo WHERE id = ?', [5],
function callback(tx, results) {
var len = [Link], i;
for (i = 0; i < len; i++) {
alert([Link](i).text);
}
},
function errorCallback(tx, error) {
alert([Link]);
}
);
});

La función de callback recibe como argumentos la transacción (de nuevo) y un objeto que
contiene los resultados. Este objeto contiene una propiedad rows , donde [Link](i)
contiene la representación de la fila concreta. Si nuestra tabla contiene un campo que se llama
nombre, podemos acceder a dicho campo de la siguiente manera:

[Link](i).nombre

8.2.4 CREAR TABLAS


La primera tarea a realizar cuando trabajamos con una base de datos es crear las tablas
necesarias para almacenar los datos. Como hemos comentado antes, este proceso se realiza a
través de una sentencia SQL, dentro de una transacción. Vamos a crear una base de datos para
almacenar tweets que posteriormente obtendremos de internet:

db = openDatabase('tweetdb', '1.0', 'All my tweets', 2 * 1024 * 1024);


[Link](function (tx) {
[Link]('CREATE TABLE IF NOT EXISTS tweets(id, user, date, tex
t)', [], getTweets);
});

8.2.5 INSERTAR DATOS


Una vez creada la tabla, el siguiente paso es insertar los datos correspondientes. Vamos a
suponer que hemos realizado una petición AJAX a la API de Twitter, que nos ha devuelto una
serie de tweets que queremos almacenar en nuestra base de datos. La función getTweets
tendría este aspecto:

function getTweets() {
var tweets = $.ajax({...});
$.each(tweets, function(tweet) {
[Link](function (tx) {
var time = (new Date([Link](tweet.created_at))).getTime
();
[Link]('INSERT INTO tweets (id, user, date, text) VAL
UES (?, ?, ?, ?)',
[[Link], tweet.from_user, time / 1000, twee
[Link]]);
});
});
}

Nota

Insertando cada tweet en una nueva transacción, nos aseguramos que si se produce un
error en alguna de ellas (ya existía el tweet), se van a seguir ejecutando el resto
transacciones.

8.2.6 OBTENER DATOS


Finalmente, una vez que los datos se encuentran almacenados en la base de datos, sólo nos
queda consultarlos. Como siempre, ejecutamos las sentencia SQL dentro de una transacción y
proveemos la función que procesará los datos obtenidos:

[Link](function (tx) {
[Link]('SELECT * FROM tweets WHERE date > ?', [time],
function(tx, results) {
var html = [], len = [Link];
for (var i = 0; i < len; i++) {
[Link]('<li>' + [Link](i).text
+ '</li>');
}
[Link] = [Link]('');
});
});

Ejercicio 9

Ver enunciado

8.3 INDEXEDDB
IndexedDB no es una base de datos relacional, sino que se podría llamar un almacén de
objetos ya que en la base de datos que creemos, existen almacenes y en su interior añadimos
objetos (como el siguiente):

{
id:21992,
nombre: "Memoria RAM"
}

En IndexedDB , al igual que en Web SQL, al abrir una base de datos debemos indicar su
nombre y la versión concreta. Posteriormente debemos crear los almacenes de objetos, que es
muy parecido a un archivador con índices, que nos permite encontrar de una manera muy
rápida el objeto que buscamos. Una vez el almacén está listo, podemos almacenar cualquier
tipo de objeto con el índice que definamos. No importa el tipo de objeto que almacenemos, ni
tienen que tener las mismas propiedades.

8.3.1 CREANDO Y ABRIENDO LA BD


De forma similar a como hacíamos en Web SQL, vamos a abrir una base de datos, y trabajar
directamente con el objeto que nos devuelve. De nuevo, al igual que en Web SQL, las peticiones
a la base de datos se realizan de manera asíncrona.

[Link] = [Link] || [Link] || windo


[Link];

if ('webkitIndexedDB' in window) {
[Link] = [Link];
[Link] = [Link];
}

var request = [Link]('videos');


[Link] = function () {
[Link]('failed to open indexedDB');
};
[Link] = function (event) {
// handle version control
// then create a new object store
};

Ahora que la base de datos esta abierta (y asumiendo que no hay errores), se ejecutará el
evento onsuccess . Antes de poder crear almacenes de objetos, tenemos que tener en cuenta
los siguiente:

• Necesitamos un manejador para poder realizar transacciones de inserción y obtención


de datos.

• Hay que especificar la versión de la base de datos. Si no existe una versión definida,
significa que la base de datos no está aún creada.

El método onsuccess recibe como parámetro un evento, al igual que lo hace cualquier otro
método escuchador de eventos. Dentro de este objeto, encontramos una propiedad llamada
target , y dentro de ésta otra propiedad llamada result , que contiene el resultado de la
operación. En este caso específico, [Link] contiene la base de datos que
acabamos de abrir.

var db = null;

var request = [Link]('videos');


[Link] = function (event) {
// cache a copy of the database handle for the future
db = [Link];
// handle version control
// then create a new object store
};
[Link] = function (event) {
alert('Something failed: ' + [Link]);
};

Es importante indicar que en IndexedDB , los errores que se producen escalan hasta el objeto
request . Esto quiere decir, que si un error ocurre en cualquier petición (por ejemplo una
consulta de datos), en este caso mostraría una alerta con el error.

8.3.2 CONTROL DE VERSIONES


El primer paso tras abrir la base de datos es realizar un control de versiones de la base de
datos. Podemos utilizar cualquier cadena de caracteres como identificador de la versión, pero
lo lógico es seguir un patrón típico de software, como '0.1', '0.2', etc. Al abrir la base de datos,
debemos comprobar si la versión actual de la base de datos coincide con la última versión de
la aplicación. Si son diferentes, tendremos que realizar la actualización.

var db = null, version = '0.1';

[Link] = function (event) {


// cache a copy of the database handle for the future
db = [Link];

// handle version control


if (version != [Link]) {
// set the version to 0.1
var verRequest = [Link](version);
[Link] = function (event) {
// now we're ready to create the object store!
};
[Link] = function () {
alert('unable to set the version :' + version);
};
}
};

8.3.3 CREAR ALMACENES DE OBJETOS


Tanto la primera vez que creamos nuestra base de datos, como a la hora de actualizarla,
debemos crear los almacenes de objetos correspondientes.

var verRequest = [Link](version);


[Link] = function (event) {
var store = [Link]('blockbusters', {
keyPath: 'title',
autoIncrement: false
});

// at this point we would notify our code


// that the object store is ready
};

Para este ejemplo, hemos creado un único almacén de objetos, pero lo normal es disponer de
varios y que puedan relacionarse entre ellos. El método createObjectStore admite dos
parámetros:

• name : indica el nombre del almacén de objetos.

• optionalParameters : este parámetro permite definir cual va a ser el índice de los


objetos, a través del cual se van a realizar las búsquedas y que por tanto debe ser único.
Si no deseamos que este índice se incremente automáticamente al añadir nuevos
objetos, también lo podemos indicar aquí. Al añadir un nuevo objeto, es importante
asegurarnos que disponga de la propiedad definida como índice, y que su valor sea único.

Es posible que deseemos añadir nuevos índices a nuestros objetos, con el fin de poder realizar
búsquedas posteriormente. Podemos realizarlo de la siguiente manera:
[Link]('director', 'director', { unique: false });

Hemos añadido un nuevo índice al almacén, llamado director (primer argumento), y hemos
indicado que el nombre de la propiedad del objeto es director (segundo argumento), a
través del cual vamos a realizar las búsquedas. Evidentemente, varias películas pueden tener
el mismo director, por lo que este valor no puede ser único. De esta manera, podemos
almacenar objetos de este tipo:

{
title: "Belly Dance Bruce - Final Strike",
date: (new Date).getTime(), // released TODAY!
director: "Bruce Awesome",
length: 169, // in minutes
rating: 10,
cover: "/images/[Link]"
}

8.3.4 AÑADIR OBJETOS AL ALMACÉN


Disponemos de dos métodos para añadir objetos al almacén: add y put .

• add : añade un nuevo objeto al almacén. Es obligatorio que los nuevos datos no existan
en el almacén, de otro modo esto provocaría un error de tipo ConstrainError .

• put : en cambio, éste método actualiza el valor del objeto si existe, o lo añade si no existe
en el almacén.
var video = {
title: "Belly Dance Bruce - Final Strike",
date: (new Date).getTime(), // released TODAY!
director: "Bruce Awesome",
length: 169, // in minutes
rating: 10,
cover: "/images/[Link]"
};

var myIDBTransaction =
[Link]
|| [Link]
|| { READ_WRITE: 'readwrite' };

var transaction =
[Link](['blockbusters'], myIDBTransaction.READ_WRITE);
var store = [Link]('blockbusters');
// var request = [Link](video);
var request = [Link](video);

Analizemos las tres últimas líneas, utilizadas para añadir un nuevo objeto al almacén:

1. transaction = [Link](['blockbusters'], READ_WRITE) : creamos una


nueva transacción de lectura/escritura, sobre los almacenes indicados (en este caso sólo
'blockbusters'), pero podrían ser varios si es necesario. Si no necesitamos que la
transacción sea de escritura, podemos indicarlo con la propiedad
IDBTransaction.READ_ONLY. .

2. store = [Link]('blockbusters') : obtenemos el almacén de


objetos sobre el que queremos realizar las operaciones, que debe ser uno de los
indicados en la transacción. Con la referencia a este objeto, podemos ejecutar las
operaciones de add , put , get , delete , etc.

3. request = [Link](video) : insertamos el objeto en el almacén. Si la transacción


se ha realizado correctamente, se llamará al evento onsuccess , mientras que si ha
ocurrido un error, se llamará a onerror .

8.3.5 OBTENER OBJETOS DEL ALMACÉN


El proceso para acceder a los objetos almacenados es muy similar a lo realizado para
insertarlos. Seguimos necesitando una transacción, pero en este caso de sólo lectura. El
proceso es el siguiente:

var myIDBTransaction =
[Link]
|| [Link]
|| { READ: 'read' };

var key = "Belly Dance Bruce - Final Strike";

var transaction =
[Link](['blockbusters'], [Link]);
var store = [Link]('blockbusters');
// var request = [Link](video);
var request = [Link](key);

En este caso, lo importante es que la clave (la variable key ) que hemos pasado al método
get , buscará el valor que contiene en la propiedad que hemos definido como keyPath al
crear el almacén de objetos.

** Nota **

El método get produce el mismo resultado tanto si el objeto existe en el almacén como
si no, pero con un valor undefined . Para evitar esta situación, es recomendable utilizar
el método openCursor() con la misma clave. Si el objeto no existe, el valor del
resultado es null .

Para obtener todos los objetos de un almacén, en lugar de un único objeto, debemos hacer uso
del método openCursor . Este método acepta como parámetro un objeto de tipo IDBKeyRange,
que podemos utilizar para acotar la búsqueda.

var transaction =
[Link](['blockbusters'], [Link]);
var store = [Link]('blockbusters');
var data = [];

var request = [Link]();


[Link] = function (event) {
var cursor = [Link];
if (cursor) {
// value is the stored object
[Link]([Link]);
// get the next object
[Link]();
} else {
// we’ve got all the data now, call
// a success callback and pass the
// data object in.
}
};
En ese ejemplo, abrimos el almacén de objetos al igual que lo hemos venido haciendo, pero en
lugar de obtener un único objeto con el método get , abrimos un cursor. Esto nos permite
iterar por los objetos devueltos por el cursor, todos como es este caso, o los que cumplan una
condición concreta. El objeto en concreto al que apunta el cursor en la iteración actual se
encuentra almacenado en su propiedad [Link] . Avanzar en el cursor, para obtener el
siguiente objeto, es tan sencillo como llamar al método continue() del cursor, lo que
provocará una nueva llamada al evento onsuccess , siendo nosotros los que tenemos que
controlar si el cursor ya no apunta a ningún objeto ( cursor === false ).

8.3.6 ELIMINAR OBJETOS DEL ALMACÉN


La última operación a realizar sobre el almacén de objetos, es eliminar datos existentes. De
nuevo, el proceso es prácticamente el mismo que para obtener datos:

var myIDBTransaction =
[Link]
|| [Link]
|| { READ_WRITE: 'readwrite' };

var transaction =
[Link](['blockbusters'], myIDBTransaction.READ_WRITE);
var store = [Link]('blockbusters');
var request = [Link](key);

Si queremos eliminar todos los objetos de un almacén, podemos utilizar el método clear() ,
siguiente el mismo proceso visto anteriormente.

var request = [Link]();

Ejercicio 10

Ver enunciado

ÍNDICE DE CONTENIDOS
Almacenamiento local

8.1 Web Storage

8.2 Web SQL

8.3 IndexedDB

También podría gustarte