Off-line gegevensopslag in real-world

In veel projecten komt er een moment waarop je sommige gegevens off-line moet opslaan. Het kan een vereiste zijn of alleen maar een verbetering voor uw gebruikers, maar u moet beslissen welke van de beschikbare opslagopties u in uw toepassing zult gebruiken. Dit artikel helpt u de beste te kiezen voor uw app.


Invoering

HTML5 heeft enkele off-line opslagopties geïntroduceerd. AppCache, localStorage, sessionStorage en IndexedDB. Elk van hen is geschikt voor een specifiek gebruik. AppCache kan bijvoorbeeld uw applicatie een boost geven of sommige delen ervan zonder een internetverbinding laten werken. Hieronder zal ik al deze opties beschrijven en enkele codefragmenten tonen met voorbeeldgebruik.


AppCache

Als een deel van uw toepassing (of de hele app) zonder toegang tot de server kan worden gebruikt, kunt u AppCache gebruiken om uw gebruikers in staat te stellen sommige dingen off-line te doen. Het enige wat u hoeft te doen is om een ​​manifestbestand te maken waarin u opgeeft wat in de cache moet worden geplaatst en wat niet zou moeten zijn. U kunt ook vervangingen opgeven voor de bestanden waarvoor online toegang vereist is.

Een AppCache-manifest is slechts een tekstbestand met een .appcache (aanbevolen) uitbreiding. Het begint met CACHE MANIFEST en is verdeeld in drie delen:

  • CACHE - bestanden die u hier opgeeft, worden gedownload en opgeslagen in de cache wanneer de gebruiker voor de eerste keer uw site bezoekt
  • NETWERK - hier vermeldt u de bestanden waarvoor een internetverbinding nodig is om goed te werken, ze worden nooit in de cache opgeslagen
  • TERUGVALLEN - deze bestanden worden gebruikt wanneer een online bron zonder verbinding wordt geopend

Voorbeeld

Eerst moet u het manifestbestand op uw pagina definiëren:

  ... 

U moet onthouden dat het manifestbestand moet worden geserveerd met een text / cache-manifest MIME-type, anders wordt het niet door de browser geparseerd. Vervolgens moet u het bestand maken dat u eerder hebt gedefinieerd. Laten we ons voor het doel van dit voorbeeld voorstellen dat u een informatieve website heeft met de mogelijkheid om contact met u op te nemen en opmerkingen te schrijven. U kunt gebruikers toegang geven tot de statische delen van de site en het contactformulier en opmerkingen vervangen door andere informatie, zodat het formulier en de opmerkingen niet toegankelijk zijn terwijl u offline bent.

Laten we eerst een statische inhoud definiëren:

 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

Kanttekening: een nadeel van het manifest is dat u geen jokerteken kunt gebruiken om aan te geven dat bijvoorbeeld een hele map in de cache moet worden geplaatst. U kunt alleen een jokerteken onder het gedeelte NETWERK gebruiken om aan te geven dat alle bronnen niet worden vermeld in het manifest mag niet worden gecached.

U hoeft de pagina waarop het manifest is gedefinieerd niet in cache op te slaan, deze wordt automatisch in de cache opgeslagen. Nu zullen we fallbacks definiëren voor de contact- en reactiesecties:

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

Eindelijk kunnen we een * om te voorkomen dat alle andere bronnen in de cache worden opgeslagen:

 NETWERK: *

Het eindresultaat zou er als volgt uit moeten zien:

 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: *

Een belangrijk ding om te onthouden is dat uw bronnen slechts eenmaal worden gecached. Ze worden niet in de cache opgeslagen wanneer u ze bijwerkt, alleen wanneer u het manifest wijzigt. Het is een goede gewoonte om een ​​opmerking in te voeren met een versienummer en het elke keer dat u het bestand bijwerkt te vergroten:

 CACHE MANIFEST # versie 1 CACHE: ... 

LocalStorage & SessionStorage

Deze twee opslagopties zijn handig als u iets in uw JavaScript-code wilt behouden. Met de eerste kunt u een waarde opslaan zonder een vervaldatum. Deze waarde is toegankelijk voor elke pagina met hetzelfde domein en hetzelfde protocol. U wilt bijvoorbeeld de applicatie-instellingen van de gebruiker opslaan op zijn / haar computer, zodat hij / zij deze kan aanpassen aan de computer die zij momenteel gebruiken. De tweede bevat de waarden totdat de gebruiker het browservenster (of het tabblad) sluit. Ook worden de gegevens niet gedeeld tussen vensters, zelfs als de gebruiker een paar pagina's van uw toepassing opent.

Iets dat u moet onthouden, is dat u alleen basistypen kunt opslaan lokale opslag/sessionStorage. Dus alleen strings en nummers zullen werken. Al het andere zal worden opgeslagen met behulp van het is toString () methode. Als u een object wilt opslaan, moet u dit doen met JSON.stringify (als dit object een klasse is, kunt u de standaard overschrijven toString () methode om het automatisch voor u te doen).

Voorbeeld

Laten we het vorige voorbeeld beschouwen. In de opmerkingen en contactgedeelten van de site kunnen we opslaan wat de gebruiker heeft ingetypt, dus als hij / zij per ongeluk het venster sluit, zijn de waarden er nog steeds voor hem / haar om later verder te gaan. Dit zal een heel eenvoudig stuk code zijn met behulp van jQuery (aangezien we de id van een veld zullen gebruiken om het later te identificeren, moet elk van de formuliervelden een id-attribuut hebben)

 $ ('# comments-input, .contact-field'). on ('keyup', function () // laten we controleren of localStorage wordt ondersteund als (window.localStorage) localStorage.setItem ($ (this) .attr ('id'), $ (this) .val ()););

Wanneer het reactie- / contactformulier wordt verzonden, moeten we de waarde wissen. Laten we dit doen door een submit-evenement af te handelen (hier is het eenvoudigste voorbeeld):

 $ ('# comments-formulier, # contact-formulier'). on ('submit', function () // verkrijg alle velden die we hebben bewaard $ ('# comments-input, .contact-field'). (function () // krijg de ID van het veld en verwijder deze van de lokale opslag localStorage.removeItem ($ (this) .attr ('id'));););

En ten slotte zullen we bij het laden van de pagina de waarden herstellen:

 // haal alle velden op die we hebben bespaard $ ('# comments-input, .contact-field'). each (function () // ontvang veld-ID en verkrijg de waarde van lokale opslag var val = localStorage.getItem ($ (this) .attr ('id')); // als de waarde bestaat, stelt u deze in als (val) $ (this) .val (val););

IndexedDB

Dit is naar mijn mening de interessantste opslagoptie. Hiermee kunt u vrij grote hoeveelheden geïndexeerde gegevens opslaan in de browser van de gebruiker. Op deze manier kunt u complexe objecten, grote documenten, enz. Opslaan en heeft uw gebruiker toegang zonder een internetverbinding. Deze functie is handig voor allerlei soorten toepassingen - als u een e-mailclient maakt, kunt u de e-mails van de gebruiker opslaan, zodat deze later kunnen worden geopend, een fotoalbum kan foto's opslaan voor off-linegebruik of GPS-navigatie kan opslaan een bepaalde route en de lijst gaat verder.

IndexedDB is een objectgeoriënteerde database. Dit betekent dat er geen tabellen en geen SQL zijn. U slaat sleutelwaardeparen van gegevens op, waarbij sleutels tekenreeksen, getallen, datums of matrices zijn en waarden complexe objecten kunnen zijn. De database zelf is samengesteld uit winkels. Een winkel is vergelijkbaar met een tabel in een relationele database. Elke waarde moet zijn eigen sleutel hebben. Een sleutel kan automatisch worden gegenereerd, u kunt deze specificeren wanneer u de waarde toevoegt, of het kan een veld in de waarde zijn (die ook automatisch kan worden gegenereerd). Als u besluit een veld als sleutel te gebruiken, kunt u alleen JavaScript-objecten aan de winkel toevoegen (omdat eenvoudige getallen of tekenreeksen geen eigenschappen kunnen hebben zoals objecten)..

Voorbeeld

Laten we ons voor dit voorbeeld voorstellen dat we een muziekalbum hebben. Ik ga hier niet de hele muziekalbum-app bouwen. Ik zal alleen het gedeelte over de IndexedDB van de app behandelen, maar de muziekalbum-app zelf is bij dit artikel inbegrepen dat je kunt downloaden, zodat je de volledige broncode daar kunt bekijken. Eerst moeten we de database openen en de winkel maken:

 // controleer of de geïndexeerde DB wordt ondersteund als (! window.indexedDB) throw 'IndexedDB niet wordt ondersteund!'; // vervang dat natuurlijk door een gebruikersvriendelijke notification // variabele die de databaseverbinding zal behouden var db; // open de database // eerste argument is de naam van de database, ten tweede is het de versie (ik zal het een tijdje over versies hebben) var request = indexedDB.open ('album', 1); request.onerror = function (e) console.log (e); ; // dit wordt geactiveerd wanneer de versie van de database request wijzigt.onupgradeneeded = function (e) // e.target.result bevat de verbinding met database db = e.target.result; // maak een winkel om de gegevens vast te houden // eerste argument is de naam van de winkel, de tweede is voor opties // hier specificeren we het veld dat als de sleutel zal dienen en ook het automatisch genereren van sleutels met autoIncrement var objectStore = db. createObjectStore ('cds', keyPath: 'id', autoIncrement: true); // maak een index om cds te zoeken op titel // eerste argument is de indexnaam, tweede is het veld in de waarde // in het laatste argument specificeren we andere opties, hier vermelden we alleen dat de index uniek is, omdat er slechts één album zijn met de specifieke titel objectStore.createIndex ('title', 'title', unique: true); // maak een index om cd's te zoeken op band // deze is niet uniek, omdat één band verschillende albums objectStore.createIndex ('band', 'band', unique: false) kan hebben; ;

De bovenstaande code is vrij eenvoudig. U hebt waarschijnlijk de versie en de onupgradeneeded evenement. Deze gebeurtenis wordt geactiveerd wanneer de database wordt geopend met een nieuwe versie. Omdat de database nog niet bestond, vuurt het evenement en kunnen we de winkel creëren die we nodig hebben. Later voegen we twee indexen toe, een om te zoeken op titel en een om te zoeken op band. Laten we nu het proces bekijken van het toevoegen en verwijderen van albums:

 // $ toevoegen ('# add-album'). on ('klik', functie () // maak de transactie // eerste argument is een lijst met winkels die gebruikt zullen worden, tweede geeft de vlag aan // sinds we wil iets toevoegen dat we schrijftoegang nodig hebben, dus gebruiken we de vlag readvit var transaction = db.transaction (['cds'], 'readwrite'); transaction.onerror = function (e) console.log (e);; var value = ...; // read from DOM // voeg het album toe aan de winkel var request = transaction.objectStore ('cds'). add (waarde); request.onsuccess = function (e) // voeg de album naar de gebruikersinterface, e.target.result is een sleutel van het item dat is toegevoegd;); // remove $ ('. remove-album'). on ('click', function () var transaction = db.transaction (['cds'], 'readwrite'); var request = transaction.objectStore ('cds ') .verwijderen (/ * een ID kreeg van DOM, geconverteerd naar integer * /); request.onsuccess = function () // verwijder het album uit de gebruikersinterface);

Vrij eenvoudig. U moet onthouden dat alle bewerkingen in de database zijn gebaseerd op transacties om de consistentie van gegevens te behouden. Nu is het enige wat u hoeft te doen om de albums weer te geven:

 request.onsuccess = function (e) if (! db) db = e.target.result; var transaction = db.transaction (['cds']); // geen vlag omdat we alleen var store = transaction.objectStore ('cds') lezen; // open een cursor, die alle items uit de database store.openCursor (). onsuccess = functie (e) var cursor = e.target.result; if (cursor) var value = cursor.value; $ ('# albums-list tbody'). append (''+ value.title +''+ value.band +''+ value.genre +''+ waarde.jaar +''); // ga naar het volgende item in de cursor cursor.continue (); ; 

Dit is ook niet erg ingewikkeld. Zoals je kunt zien, kun je met behulp van IndexedDB complexe waarden heel eenvoudig opslaan. U kunt ook naar waarden zoeken op index, zoals deze:

 functie getAlbumByBand (band) var transaction = db.transaction (['cds']); var store = transaction.objectStore ('cds'); var index = store.index ('band'); // open een cursor om alleen albums met opgegeven band te krijgen // noteer het argument dat is doorgegeven aan openCursor () index.openCursor (IDBKeyRange.only (band)) onsuccess = function (e) var cursor = e.target.result; if (cursor) // render het album // ga naar het volgende item in de cursor cursor.continue (); ); 

U kunt de cursor met de index gebruiken, net zoals we deden met de winkel. Omdat er mogelijk enkele items zijn met dezelfde indexwaarde (als deze niet uniek is), moeten we deze gebruiken IDBKeyRange. Hierdoor worden de resultaten gefilterd, afhankelijk van welke functie u gebruikt. Hier willen we alleen items van de opgegeven band ontvangen, dus hebben we de enkel en alleen() methode. Je kan ook gebruiken onderGrens (), bovenGrens () en gebonden. De namen van de methoden zijn redelijk duidelijk.


Conclusie

Het inschakelen van off-line toegang voor uw gebruikers is dus niet zo ingewikkeld als het lijkt. Ik hoop dat je na het lezen van dit artikel je applicaties gebruiksvriendelijker zult maken door ze toegang te geven tot sommige delen (of misschien zelfs alle) zonder een internetverbinding. U kunt de voorbeeld-app downloaden en ermee experimenteren, meer opties toevoegen of sommige delen ervan opnemen in uw website.