HTML5: Un database per il browser con IndexedDB per andare oltre il Web Storage

La possibilità di gestire localmente nel browser uno storage per le applicazioni accessibile direttamente via JavaScript è sicuramente una delle funzionalità tra le più desiderate e potenzialmente utili per arricchire le applicazioni Web, incrementarne le performance, gestire sempre più la possibilità di scenari di offline. Un primo importante passo nelle specifiche HTML5 verso la possibilità di utilizzare uno storage client locale è rappresentato dalle specifiche del WebStorage che sono ampiamente supportate nei diversi browser e presenti anche in IE a partire dalla versione 8 . Il WebStorage permette però di gestire la persistenza di elementi in modo simile a quanto possibile fare con cookie superando però le limitazioni ed in particolare la complicazione non indifferente nella gestione dei cookie stessi. 

Le API del Web Storage offrono essenzialmente due oggetti il sessionStorage e il localStorage che consentono di gestire un meccanismo di persistenza per dominio in modalità per sessione o persistente. L'utilizzo è molto semplice, si usano i metodi setItem e removeItem per inserire e cancellare item utilizzando un meccanismo chiave valore . Ad esempio per inserire un valore:

localStorage.setItem("keyName","keyValue");

per rimuoverlo:

localStorage.removeItem("keyName");

Disponibili anche una buona serie di librerie che consentono di gestire il fallback sui browser che non supportano il Web Storage come ad esempio la libreria storage polyfill di Remy Sharp. 

 Ampia e continua la discussione nel W3C per ampliare il supporto nel browser per lo storage locale, allargandolo anche alla presenza di un vero e proprio database semplificato che consenta di memorizzare e gestire dati in modo strutturato e apra la strada a scenari di sincronizzazione di dati. Tra le specifiche proposte abbiamo la Web SQL Database API e la parte di IndexedDB . Quest'ultima è la specifica proposta da Oracle , Microsoft e Mozilla, su cui stanno convergendo la maggior parte dei membri del W3C, convergenza già in corso come tendenza da alcuni mesi e che comincia a concretizzarsi anche in annunci di implementazione nei browser come ad esempio per firefox. Anche per chrome sta succedendo altrettanto  con l'avvio dell'implementazione di IndexedDB e nella parte di Web SQL Database nelle specifiche del W3C si legge oramai formalmente nello status del documento: "Beware. This specification is no longer in active maintenance and the WebApplications Working Group does not intend to maintain it further" ed è quindi oramai IndexedDB la specifica candidata per l'implementazione da parte della maggior parte dei browser. Stiamo comunque parlando di specifiche di standard ancora in definizione e quindi immature per un utilizzo di applicazioni reali e che quindi vanno utilizzate con cautela, come anche i diversi vendor di browser segnalano. Ad esempio in questo post sull'implementazione nella beta di firefox leggiamo "Keep in mind that IndexedDB is brand new and is not uniformly supported by all browsers, and please file bugs for any behavior that seems to contradict the specification!". 

Il Web è una piattaforma in continua evoluzione, e ci sarà sempre una tensione tra gli sviluppatori che desiderano utilizzare le tecnologie più recenti e le specifiche ufficiali ancora non consentono, e gli sviluppatori di applicazioni di business che vogliono costruire qualcosa per una specifica che si aspettano stabile e supportata per un decennio. Non in tutte le situazioni è possibile aggiornare i browser e le applicazioni ogni notte o anche ogni settimana, ma al tempo stesso è anche importante avere la possibilità di valutare l'implementazione di specifiche ancora non complete e di stimolare e partecipare all'implemetazione delle stesse.

Per permettere il test delle specifiche in evoluzione e garantire allo stesso tempo, una chiara e netta suddivisione tra le specifiche stabili ed utilizzabili e la parte di specifiche sperimentali, Microsoft sta adottando nello sviluppo di IE un approccio differente rispetto ad altri browser che inserisco e modificano le implementazioni direttamente nelle build , generando anche situazioni di confusione come successo recentemente con i websocket (https://hacks.mozilla.org/2010/12/websockets-disabled-in-firefox-4/) . Nelle preview e nelle beta ed a maggior ragione nelle release finali delle varie versioni di IE, vengono inserite soltanto le implementazioni delle specifiche che sono sufficientemente mature, documentate e che hanno la garanzia di un comportamento uniforme nelle diverse implementazioni nei vari browser. Per consentire invece, la sperimentazione anche della parte di specifiche in evoluzione e che sono candidate ad una futura implementazione uniforme, sono stati appunto creati gli HTML5 Labs . Attraverso gli HTML5 Labs si possono aggiungere al browser delle implementazioni sperimentali delle nuove specifiche e cominciare a provarle utilizzandole in modo controllato, avendo così una netta separazione tra gli elementi stabili da quelli in forte evoluzione, garantendo pienamente gli sviluppatori rispetto alla stabilità e la compatibilità delle implementazioni supportate nel browser.

Tra le specifiche disponibili come componenti aggiuntivi su HTML5 Labs abbiamo appunto l'implementazione di IndexedDB che possiamo scaricare dal sito e registrare localmente sul nostro PC per sperimentarla utilizzando IE 9. Si come già detto, di una implementazione per test  realizzata attraverso un ActiveX. Nel package scaricato da HTML5 Labs troviamo un readme introduttivo che spiega come configurare e registrare il componente aggiuntivo , un file js di base che carica il componente nella pagina e genera delle variabili per consentire un utilizzo diretto dei metodi dell'ActiveX da JS e una serie di esempi che illustrano il funzionamento delle API implementate al momento secondo .  

 IndexedDB prevede essenzialmente delle API con due modalità di utilizzo: sincrono e asincrono. Si possono creare dei database locali comuni ad uno specifico dominio. Attraverso le API si possono gestire gestione dei dati avanzate attraverso la gestione di indici per l'accesso ai dati. Si possono anche utilizzare delle transazioni per la gestione di più operazioni sui dati e vengono usati dei di dati persistenti in una struttura B-tree che permettono in modo efficace l'inserimento, cancellazione, e accesso in-order anche di un numero elevato di record di dati.

Di seguito riporto un semplice esempio di creazione\accesso ad un database locale con la parte di API sincrone:

try
{
var db = indexedDBSync.open(indexedDBName, indexedDBDescription);
if (db)
{
db.setVersion("1.0");

var sName = db.name;
var dVersion = db.version;
var dTableNames = db.objectStoreNames;
var strNames = "IndexedDB name: " + sName
+ "; version: " + dVersion + "; object stores: ";
for (var i = 0; i < dTableNames.length; i++) {
strNames = strNames + dTableNames[i] + ", ";
}

alert(strNames);

                db.close();
}
}
catch (e)
{
alert("Error: " + e.message);
}

Si possono poi creare degli indici e inserire contenuti ed accederci direttamente attrraverso l'indice stesso ed il semplice esempio descrittivo che trovate nella specifica e che riporto di seguito da un idea della modalità di utilizzo:

 

var db = indexedDB.open('books', 'Book store', false);
if (db.version !== '1.0') {
var olddb = indexedDB.open('books', 'Book store');
olddb.createObjectStore('books', 'isbn');
olddb.createIndex('BookAuthor', 'books', 'author', false);
olddb.setVersion("1.0");
}
// db.version === "1.0";
var index = db.openIndex('BookAuthor');
var matching = index.get('fred');
if (matching)
report(matching.isbn, matching.name, matching.author);
else
report(null);

 

Nel caso di utilizzo delle API asincrone si possono impostare direttamente le funzioni su cui essere richiamati ad esecuzione ultimata come nel seguente esempio tratto sempre dal documento della specifica:

 

function findFred() {
var store = db.objectStore('books');
var index = store.index('BookAuthor');
var req = index.get('fred');
req.onsuccess = function(event) {
var matching = event.result;
report(matching.isbn, matching.name, matching.author);
}
req.onerror = function(event) {
report(null);
}
}

 

Scaricando l'implementazione di test da HTML5 Labs, trovate ulteriori esempi per poter approfondire l'utilizzo di questa specifica in elaborazione.

UPDATED 4-feb-2011:

Aggiornata l'implementazione su HTML5 Labs di Indexed DB . Informazioni sull'aggiornamento nel blog https://blogs.msdn.com/b/interoperability/archive/2011/02/03/the-indexeddb-prototype-gets-an-update.aspx