Memorizzazione di dati off-line Real-World

In molti progetti arriva un momento in cui è necessario memorizzare alcuni dati off-line. Potrebbe essere un requisito o solo un miglioramento per i tuoi utenti, ma devi decidere quali delle opzioni di archiviazione disponibili utilizzerai nella tua applicazione. Questo articolo ti aiuterà a scegliere il migliore, per la tua app.


introduzione

HTML5 ha introdotto alcune opzioni di archiviazione off-line. AppCache, localStorage, sessionStorage e IndexedDB. Ognuno di essi è adatto per un uso specifico. Ad esempio, AppCache può potenziare l'applicazione o lasciare che alcune parti di esso funzionino senza una connessione Internet. Di seguito, descriverò tutte queste opzioni e mostrerò alcuni snippet di codice con l'utilizzo di esempio.


AppCache

Se una parte della tua applicazione (o l'intera app) può essere utilizzata senza accesso al server, puoi utilizzare AppCache per consentire agli utenti di fare alcune cose offline. Tutto quello che devi fare è creare un file manifest dove devi specificare cosa dovrebbe essere memorizzato nella cache e cosa non dovrebbe essere. È inoltre possibile specificare sostituzioni per i file che richiedono l'accesso in linea.

Un manifest AppCache è solo un file di testo con a .AppCache (consigliato) estensione. Inizia con CACHE MANIFEST ed è diviso in tre parti:

  • CACHE - i file che specifichi qui verranno scaricati e memorizzati nella cache la prima volta che l'utente accede al tuo sito
  • RETE - qui elencherai i file che richiedono una connessione Internet per funzionare correttamente, non verranno mai memorizzati nella cache
  • RICADERCI - questi file verranno utilizzati quando si accede a una risorsa online senza una connessione

Esempio

Innanzitutto, devi definire il file manifest sulla tua pagina:

  ... 

È necessario ricordare che il file manifest deve essere servito con a text / cache-manifest Tipo MIME, altrimenti non verrà analizzato dal browser. Successivamente, è necessario creare il file definito in precedenza. Ai fini di questo esempio, immaginiamo di disporre di un sito Web informativo con la possibilità di contattarti e scrivere commenti. Puoi consentire agli utenti di accedere alle parti statiche del sito e sostituire il modulo di contatto e i commenti con altre informazioni in modo che il modulo e i commenti non siano accessibili mentre sono offline.

Innanzitutto, definiamo alcuni contenuti statici:

 CACHE MANIFEST CACHE: /about.html /portfolio.html /portfolio_gallery/image_1.jpg /portfolio_gallery/image_2.jpg /info.html /style.css /main.js /jquery.min.js

Nota a margine: una cosa negativa del manifest è che non è possibile utilizzare un segno jolly per indicare che, ad esempio, un'intera cartella deve essere memorizzata nella cache, è possibile utilizzare solo un carattere jolly nella sezione NETWORK per indicare che tutte le risorse non sono elencate nel manifest non dovrebbe essere memorizzato nella cache.

Non è necessario memorizzare nella cache la pagina in cui è definito il manifest, verrà memorizzato automaticamente nella cache. Ora definiremo i fallback per le sezioni contatti e commenti:

 FALLBACK: /contact.html /offline.html /comments.html /offline.html

Infine, possiamo usare un * per impedire che tutte le altre risorse vengano memorizzate nella cache:

 RETE: *

Il risultato finale dovrebbe assomigliare a questo:

 CACHE MANIFEST CACHE: /about.html /portfolio.html /portfolio_gallery/image_1.jpg /portfolio_gallery/image_2.jpg /info.html /style.css /main.js /jquery.min.js FALLBACK: /contact.html / offline .html /comments.html /offline.html NETWORK: *

Una cosa importante da ricordare è che le tue risorse verranno memorizzate solo una volta. Non verranno memorizzati nella cache quando li aggiorni, solo quando cambi il manifest. Una buona pratica è inserire un commento con un numero di versione e aumentarlo ogni volta che si aggiorna il file:

 CACHE MANIFEST # versione 1 CACHE: ... 

LocalStorage & SessionStorage

Queste due opzioni di archiviazione saranno utili se desideri conservare qualcosa nel tuo codice JavaScript. Il primo consente di salvare un valore senza una data di scadenza. Questo valore sarà accessibile per qualsiasi pagina con lo stesso dominio e protocollo. Ad esempio, potresti voler salvare le impostazioni dell'applicazione dell'utente sul suo computer in modo che lui / lei possa regolarle sul computer che attualmente usano. Il secondo manterrà i valori finché l'utente non chiude la finestra del browser (o scheda). Inoltre, i dati non vengono condivisi tra le finestre, anche se l'utente apre alcune pagine dell'applicazione.

Qualcosa che vale la pena ricordare è che puoi memorizzare solo i tipi di base in memoria locale/sessionStorage. Quindi solo le stringhe e i numeri funzioneranno. Tutto il resto verrà memorizzato usando di esso accordare() metodo. Se hai bisogno di salvare un oggetto, dovresti farlo usando JSON.stringify (se questo oggetto è una classe, puoi semplicemente sovrascrivere il valore predefinito accordare() metodo per farlo automaticamente).

Esempio

Consideriamo l'esempio precedente. Nei commenti e nelle sezioni di contatto del sito, possiamo salvare ciò che l'utente ha digitato, quindi se chiude accidentalmente la finestra, i valori saranno ancora lì per lui / lei a continuare in seguito. Questa sarà una parte di codice molto semplice usando jQuery (poiché utilizzeremo l'ID di un campo per identificarlo in un secondo momento, ognuno dei campi del modulo dovrà avere un attributo id)

 $ ('# comments-input, .contact-field'). on ('keyup', function () // controlliamo se localStorage è supportato if (window.localStorage) localStorage.setItem ($ (this) .attr ('id'), $ (this) .val ()););

Quando viene inviato il modulo di commento / contatto, dobbiamo cancellare il valore. Facciamo ciò gestendo un evento di invio (ecco l'esempio più semplice):

 $ ('# commenti-form, # contact-form'). on ('submit', function () // richiama tutti i campi che abbiamo salvato $ ('# comments-input, .contact-field'). (function () // ottiene l'id del campo e lo rimuove dall'archivio locale localStorage.removeItem ($ (this) .attr ('id'));););

E infine, al caricamento della pagina, ripristineremo i valori:

 // recupera tutti i campi che abbiamo salvato $ ('# comments-input, .contact-field'). each (function () // ottiene l'id del campo e ottiene il valore dalla memoria locale var val = localStorage.getItem ($ (this) .attr ('id')); // se il valore esiste, impostalo se (val) $ (this) .val (val););

IndexedDB

Questa è l'opzione di archiviazione più interessante a mio parere. Permette di memorizzare quantità piuttosto grandi di dati indicizzati nel browser dell'utente. In questo modo è possibile salvare oggetti complessi, documenti di grandi dimensioni, ecc. E consentire all'utente di accedervi senza una connessione Internet. Questa funzione è utile per tutti i tipi di applicazioni: se si sta creando un client di posta elettronica, è possibile salvare le e-mail dell'utente in modo che possa accedervi in ​​un secondo momento, un album di foto può salvare foto per l'uso offline o la navigazione GPS può salvare un percorso particolare e la lista continua.

IndexedDB è un database orientato agli oggetti. Ciò significa che non ci sono tabelle e SQL. Si memorizzano coppie di dati valore-chiave, dove le chiavi sono stringhe, numeri, date o matrici e i valori possono essere oggetti complessi. Il database stesso è composto da negozi. Un negozio è simile a una tabella in un database relazionale. Ogni valore deve avere la propria chiave. Una chiave può essere generata automaticamente, è possibile specificarla quando si aggiunge il valore o può essere un campo nel valore (che può anche essere generato automaticamente). Se decidi di utilizzare un campo come chiave, sarai in grado di aggiungere oggetti JavaScript all'archivio (perché numeri semplici o stringhe non possono avere proprietà come gli oggetti).

Esempio

Per questo esempio, immaginiamo di avere un album musicale. Ora, non ho intenzione di coprire la costruzione dell'intera app per album musicali qui. Coprirò solo la parte IndexedDB dell'app, ma l'app dell'album musicale è inclusa in questo articolo per il download, quindi puoi consultare il codice sorgente completo lì. Innanzitutto, dobbiamo aprire il database e creare lo store:

 // controlla se indexedDB è supportato se (! window.indexedDB) throw 'IndexedDB non è supportato!'; // ovviamente sostituiscilo con una variabile di notifica user-friendly // che manterrà la connessione al database var db; // apre il database // il primo argomento è il nome del database, il secondo è la sua versione (parlerò delle versioni in un istante) var request = indexedDB.open ('album', 1); request.onerror = function (e) console.log (e); ; // questo si attiva quando la versione del database cambia request.onupgradeneeded = function (e) // e.target.result mantiene la connessione al database db = e.target.result; // crea un negozio per contenere i dati // il primo argomento è il nome del negozio, il secondo è per le opzioni // qui si specifica il campo che servirà come chiave e si abilita anche la generazione automatica di chiavi con autoIncrement var objectStore = db. createObjectStore ('cds', keyPath: 'id', autoIncrement: true); // crea un indice per cercare i CD per titolo // il primo argomento è il nome dell'indice, il secondo è il campo nel valore // nell'ultimo argomento specifichiamo altre opzioni, qui si afferma solo che l'indice è univoco, perché non ci può essere solo un album con titolo specifico oggettoStore.createIndex ('titolo', 'titolo', unique: true); // crea un indice per cercare cd per banda // questo non è univoco, poiché una band può avere diversi album objectStore.createIndex ('band', 'band', unique: false); ;

Il codice sopra è piuttosto semplice. Probabilmente hai notato la versione e il onupgradeneeded evento. Questo evento viene generato quando il database viene aperto con una nuova versione. Poiché il database non esisteva ancora, l'evento si attiva e possiamo creare lo store di cui abbiamo bisogno. Successivamente aggiungeremo due indici, uno per la ricerca per titolo e l'altro per la ricerca per banda. Ora vediamo il processo di aggiunta e rimozione di album:

 // aggiungendo $ ('# add-album'). on ('click', function () // crea la transazione // primo argomento è una lista di negozi che verranno utilizzati, seconda specifica la flag // poiché voglio aggiungere qualcosa abbiamo bisogno di accesso in scrittura, quindi usiamo readwrite flag var transaction = db.transaction (['cds'], 'readwrite'); transaction.onerror = function (e) console.log (e);; var value = ...; // read from DOM // aggiungi l'album al negozio var request = transaction.objectStore ('cds'). add (valore); request.onsuccess = function (e) // aggiungi album sull'interfaccia utente, e.target.result è una chiave dell'elemento che è stato aggiunto;); // remove $ ('. remove-album'). on ('click', function () var transaction = db.transaction (['cds'], 'readwrite'); var request = transaction.objectStore ('cds ') .delete (/ * qualche ID ottenuto dal DOM, convertito in intero * /); request.onsuccess = function () // rimuove l'album dall'interfaccia utente);

Abbastanza diretto. È necessario ricordare che tutte le operazioni sul database si basano sulle transazioni per preservare la coerenza dei dati. Ora l'unica cosa che resta da fare è mostrare gli album:

 request.onsuccess = function (e) if (! db) db = e.target.result; var transaction = db.transaction (['cds']); // nessun flag dato che stiamo leggendo solo var store = transaction.objectStore ('cds'); // apre un cursore, che otterrà tutti gli elementi dal database store.openCursor (). onsuccess = function (e) var cursor = e.target.result; if (cursor) var value = cursor.value; $ ('# album-list tbody'). append (''+ value.title +''+ value.band +''+ value.genre +''+ value.year +''); // passa all'elemento successivo nel cursore cursor.continue (); ; 

Anche questo non è molto complicato. Come puoi vedere, con IndexedDB puoi memorizzare facilmente valori complessi. Puoi anche cercare valori per indice, in questo modo:

 function getAlbumByBand (band) var transaction = db.transaction (['cds']); var store = transaction.objectStore ('cds'); var index = store.index ('band'); // apre un cursore per ottenere solo gli album con una banda specifica // nota l'argomento passato a openCursor () index.openCursor (IDBKeyRange.only (banda)). onsuccess = function (e) var cursor = e.target.result; if (cursor) // rende l'album // sposta all'elemento successivo nel cursore cursor.continue (); ); 

Puoi usare il cursore con l'indice proprio come abbiamo fatto con il negozio. Dal momento che potrebbero esserci alcune voci con lo stesso valore di indice (se non è univoco) dobbiamo usare IDBKeyRange. Questo filtrerà i risultati a seconda della funzione che usi. Qui, vogliamo ottenere solo gli elementi dalla banda fornita, quindi abbiamo usato il solo() metodo. Puoi anche usare limite inferiore(), limite superiore() e limite. I nomi dei metodi sono piuttosto auto-esplicativi.


Conclusione

Quindi abilitare l'accesso offline per i tuoi utenti non è così complicato come potrebbe sembrare. Spero che dopo aver letto questo articolo renderete le vostre applicazioni più user-friendly, consentendo loro di accedere ad alcune parti (o forse anche tutte) di esso senza una connessione Internet. Puoi scaricare l'app di esempio e sperimentarla, aggiungendo altre opzioni o includendone alcune parti nel tuo sito web.