Hinweis: Am 9. April beteiligen wir uns auf webkrauts.de am Naked CSS Day. Die Stylesheets sind an diesem Tag absichtlich abgeschaltet.

Webkrauts Logo

Webkrauts Webkrauts Schriftzug

- für mehr Qualität im Web

HTML5 als Geschenkverpackung von Daten

HTML5 als Geschenkverpackung von Daten

Cookies nerven. Andererseits ist es durchaus sinnvoll, in bestimmten Fällen Daten beim Nutzer zu speichern. Christian Heilmann stellt eine einfachere und standardisierte Lösung vor: die Local Storage API.

Gemälde (Ausschnitt): Antoine Watteau, Das Ladenschild des Kunsthändlers Gersaint, 1720/21. Schloss Charlottenburg, Berlin.

HTML5 verändert das Web von einem Web der Hacks zu einem Web der Applikationen. Wir sind auf dem Weg, dieses Ziel sehr bald zu erreichen, und das kommende Jahr wird für die, die sich für Web-Technologien interessieren, sehr spannend werden.

Schon in diesem Jahr haben wir die Anfänge der HTML5-Revolution erlebt, und es gibt nichts, was diesen Umschwung stoppen kann. Zum allerersten mal arbeiten Browserhersteller eng miteinander, um eine Technologie schnell voran zu bringen. Die neuen Browserkriege drehen sich darum, den Standard HTML5 bestmöglichst in den eigenen Browser einzubauen, anstatt sich auf eigene Erfindungen, die nur in einem Browser funktionieren, zu konzentrieren. Wir leben in interessanten Zeiten.

Feuerwerk als Vorspeise

Wie bei jeder Revolution gibt es erstmal eine Menge Lärm und Explosionen, und das ist der Punkt, in dem wir uns derzeit bewegen. Viele HTML5 Beispielseiten sind eigentlich CSS3-Demos, Web-Fonts-Beispiele oder Video/Canvas-Shows.

Das ist schön und gut, da es Interesse weckt und den Medien etwas zum Anzeigen gibt. HTML5 ist allerdings viel mehr als schöne Effekte. Daher wenden wir uns jetzt einmal einem HTML5-Aspekt zu, der weniger sexy aber sehr praktisch ist: Datenspeicherung auf dem Rechner des Users. Diese Technik ist mitlerweile so weit gewachsen, dass sie zu einer eigenen Spezifikation befördert wurde.

Wozu Daten auf dem Rechner des Users speichern?

Datenspeicherung im Browser gibt uns eine Funktionalität, die bislang nur mit installierten Applikationen möglich war:

  • Speicherung des aktuellen Applikationszustandes – Wenn der Benutzer nach dem Schließen des Browsers zu einer Applikation zurückkehrt, sollte diese so dargestellt werden, wie sie zuletzt verlassen wurde. So funktionieren Desktop-Applikationen auch.
  • Zwischenspeicherung von Daten – wenn ein Datensatz sich nicht ändert, macht es auch keinen Sinn, diesen über das Internet zu laden, wenn wir ihn auch viel schneller lokal aufrufen können.
  • Speicherung der Userkonfiguration ohne diese Daten auf dem Server zu speichern.

Die Probleme mit halbfertigen Browserlösungen

In der Vergangenheit war das Speichern von Daten auf dem Rechner des Users keine Freude, denn es gab nur Cookies. Cookies nerven – es macht einfach keinen Spaß, unverschlüsselte HTTP-Anfragen bei jedem Ladevorgang zu ertragen, nur um 4K Daten in einem kryptischen Format auf dem Computer des Benutzers abzulegen.

Dann kam eine Fülle von verschiedenen Lösungen von verschiedenen Anbietern – von Microsofts userdata über Flashs LSO, Silverlights isolated storage bis hin zu Google-Gears. Wer herausfinden möchte, wie viele verrückte und fehlgeleitete Möglichkeiten es gibt, kann sich mal den Quellcode von Samys evercookie anschauen.

Wir brauchen hingegen eine einfachere und standardisierte Lösung, um Daten auf den Rechnern unserer Besucher abzulegen.

Machen wir es uns einfach – Local Storage

Es gibt eine einfache Lösung: die anwendbare Local Storage API. Alles, was benötigt wird, sind ein paar Methoden des window.localStorage Objekts – oder eben die verkürzte Klammerschreibweise:

  1. // kann der Browser local storage?
  2.   if('localStorage' in window && window['localStorage'] !== null){
  3.  
  4.   // ja, also speichern wir ein Kürzel
  5.     var store = window.localStorage;
  6.  
  7.   // der API Weg
  8.     store.setItem('Hund','Wau');
  9.     console.log(
  10.       store.getItem('Hund')
  11.     ); // => 'Wau'
  12.  
  13.   // Kurzschreibweise, ein Fehler mit Schlüsseln, die Leerzeichen
  14.   // beinhalten
  15.     store.Katze = 'Miau'
  16.     console.log(
  17.       store.Katze
  18.     ); // 'Miau'
  19.  
  20.   // Kurzschreibweise für alle Schlüssel
  21.     store['Kuh'] = 'Wen kenne ich, der Sperren im Internet aktiv umgehen kann?'
  22.     console.log(
  23.       store['Kuh']
  24.     ); // => 'Wen kenne ich, der Sperren im Internet aktiv umgehen kann?'
  25.  
  26.   }

Die Unterstützung von Browsern ist beindruckend: IE8+, Firefox 3.5+, Safari 4+, Chrome 4+, Opera 10.5+, iPhone 2.0+ and Android 2.0+ verstehen alle localStorage. Das sollte die meisten Kunden abdecken. Nichtsdestrotrotz ist es wichtig, zu testen, ob localStorage benutzt werden kann. Um auch älteren Browsern das beizubringen, gibt es Bibliotheken wie YUI Storage oder YUI Storage Lite. Die Daten werden per Domain abgelegt, und es werden 5MB Speicherplatz geboten.

Nur für Texte

Die Voreinstellung von localStorage ist, dass Daten nur als Strings abgelegt werden können. Das bedeutet, dass wir nicht einfach Ergebnisse von Funktionen oder Berechnungen ablegen können. Außerdem verbrauchen Fließkommazahlen als Strings deutlich mehr Speicherplatz.

  1. var wiesel = "Das Wiesel saß auf einem Kiesel inmitten Bachgeriesel. "+
  2.              "Wisst ihr warum? Das Mondkalb verriet es mir im Stillen - "+
  3.              "das Schlaue Tier tats um des Reimes Willen!";
  4.  
  5. var wieseldef = {
  6.   "Lage":{
  7.     "z":Kiesel.top-1,
  8.     "x":Bachgeriesel.width/2,
  9.     "y":Bachgeriesel.height/2,
  10.   },
  11.   "Grund":"Reim"
  12. };
  13.  
  14. window.localStorage.setItem('Wieselbeschreibung',wiesel);
  15. console.log(
  16.   window.localStorage.getItem('Wieselbeschreibung')
  17. ); // => Das Wiesel saß auf einem Kiesel...
  18.  
  19. window.localStorage.setItem('Wieseldefinition',wieseldef);
  20. console.log(
  21.   window.localStorage.getItem('wieseldef')
  22. ); // => [object Object] = Autsch!

Das hindert uns stark in den Möglichkeiten, Daten zu speichern. Allerdings wird es einfacher, wenn wir die Daten einfach in JSON umwandeln:

  1. var wieseldef = {
  2.   "Lage":{
  3.     "z":Kiesel.top-1,
  4.     "x":Bachgeriesel.width/2,
  5.     "y":Bachgeriesel.height/2,
  6.   },
  7.   "Grund":"Reim"
  8. };
  9.  
  10. window.localStorage.setItem('Wieseldefinition',JSON.stringify(wieseldef));
  11. console.log(
  12.   JSON.parse(
  13.     window.localStorage.getItem('Wieseldefinition')
  14.   )
  15. ); // =>  Object { Lage, more...}

Natürlich können wir auch unser eigenes, String-basiertes Datenformat erfinden oder CSV verwenden, doch JSON hat den Vorteil, dass es sehr klein ist und nativ von Browsern unterstützt wird.

Ein paar Beispiele

Das einfachste Beispiel, um zu zeigen wie praktisch localStorage ist, ist es einfach Daten abzulegen – einen Spielstand, den Status eines mehrseitigen Formulars und andere Daten, die bislang in Cookies gespeichert wurden. Mittels JSON können wir allerdings auch Interessanteres angehen.

Schnellere Nutzung von Web Services und Umgehung der Quotasperre

Viele Web Services erlauben einem nur eine bestimmte Anzahl von Abfragen pro Stunde – andere sind ziemlich langsam. Mittels localStorage und einem Verfallsdatum können wir die Daten von Webservices lokal speichern und nur nach einer bestimmten Zeit neu anfordern, um einen frischeren Datensatz zu erhalten.

Dieser Trick wird beispielsweise in meinem Eintrag »World Info« für den »An Event Apart 10K« Wettbewerb verwendet, um den massiven Datensatz der Ländernamen und Daten nur einmal zu laden und bei den folgenden Besuchen blitzschnell vom lokalen Rechner zu lesen. Der folgende Screencast zeigt den Unterschied: Das zweite Mal benötigt die Seite viel weniger Ladezeit.

Um YQL (errinnert Ihr Euch an mein Türchen vom Adventskalender im letzten Jahr?) mit localStorage zu verwenden, habe ich mir ein kleines Skript erstellt:YQL localcache. Zum Beispiel:

  1. yqlcache.get({
  2.   yql: 'select * from flickr.photos.search where text="gurken"',
  3.   id: 'meinegurkenphotos',
  4.   cacheage: ( 60*60*1000 ),
  5.   callback: function(data) {
  6.     console.log(data);
  7.   }
  8. });

Mit diesem Aufruf lädt man Fotos von »Gurken« von Flickr und speichert diese für eine Stunde in dem Schlüssel meinegurkenphotos von localStorage. Wenn wir die Funktion anschließend noch einmal aufrufen, bekommen wir ein Objekt zurück mit den YQL-Ergebnissen als Eigenschaft data und einer type-Eigenschaft, die beschreibt, wo die Daten herkommen. Das »live« steht für frische Daten (Browser, die kein localStorage verstehen, bekommen immer diese Daten zurück), »cached« bedeutet, die Daten kommen aus dem Speicher und »freshcache« bedeutet, dass der Speicher erneuert wurde. Der Speicher wird für eine Stunde (60*60*1000 Millisekunden) angelegt und erneuert, wenn eine Stunde vergangen ist und der Nutzer die Daten anfordert. Alles in allem bedeutet das, dass man YQL nur einmal pro Stunde anfragt, anstatt bei jedem Aufruf.

Zwischenspeicherung eines Interfaces

Eine weitere praktische Anwendung von localStorage ist die Speicherung des aktuellen Standes eines Interfaces. Wir können dafür einfach das innerHTML eines HTML-Elementes nehmen und in localStorage ablegen. Ich verwende diesen Trick im Yahoo Firehose search interface und erkläre die Idee und den Gedankengang im folgenden Screencast:

Das vereinfachte Script ist eine Mischung aus JavaScript und PHP:

  1. // geht localStorage?
  2.   if(('localStorage' in window) && window['localStorage'] !== null){
  3.  
  4.   var f = document.getElementById('meinformular');
  5.  
  6. // wurde das Formular abgeschickt?
  7. // (der Abschickbutton hatte den Namen "machhinne")
  8.   <?php if(isset($_POST['machhinne']))){?>
  9.  
  10. // nehme das derzeitige HTML und speichere es in "formularstatus"
  11.       localStorage.setItem('formularstatus',f.innerHTML);
  12.  
  13. // wenn das Formular nicht abgeschickt wurde...
  14.   <?php }else{ ?>
  15.  
  16. // teste ob es einen Schlüssel mit dem Namen "formularstatus" gibt
  17. // und überschreibe das HTML im Formular mit dem Inhalt
  18.     if('formularstatus' in localStorage){
  19.       f.innerHTML = localStorage.getItem('formularstatus');
  20.     }
  21.  
  22.   <?php } ?>
  23.  
  24.   }

Noch mehr Ideen

Local Storage ist immer dann sinnvoll, wenn wir den Zugriff auf Daten schneller gestalten wollen. Zum Beispiel könnten wir Bildsprites als base64 Datensätze ablegen, anstatt sie von einem Server zu laden (ein Trick der auf Handys und in GreaseMonkey Skripten schon lange verwendet wird). Eine weitere Idee ist es, CSS und JavaScript Bibliotheken auf dem Rechner des Besuchers abzulegen. Alles ist möglich – Zeit zum Spielen!

Probleme mit local und session Storage

Natürlich ist nicht alles Gold, was glänzt, in der localStorage-API. Ein paar Probleme müssen noch von den Browserherstellern und den Standardisten ausgebügelt werden. Hier eine kleine Auswahl:

  • Fehlende Information über die Speichergrösse – wenn jemand versucht, mehr Daten abzulegen als der Browser erlaubt, gibt es einen QUOTA_EXCEEDED_ERR als Antwort und nicht mehr. Wir können den Endnutzer nicht nach mehr Speicherplatz fragen – das kann sich aber bald ändern. Wir haben schon ein paar Testfälle mit Erklärungen, die derzeit untersucht werden.
  • Gespeicherte Daten können sich nicht automatisch nach einer gewissen Zeit löschen – mit Cookies war das kein Thema. Pamela Fox hat eine Lösung für das Problem (auch als Beispiel und Source Code erhältlich)
  • Keine Verschlüsselung von Daten – derzeit sind alle Daten als Strings im Speicher, und wir können sie mit Firebug abrufen, da JavaScript noch kein Domainsicherheitssystem hat (auch daran wird gearbeitet).

Grösser, schneller, besser, mehr!

Local Storage ist praktisch, doch wenn man größere Lösungen angehen will, wird ein key/value-Store bald nicht mehr ausreichen. Außerdem haben wir seit Jahren Datenbanken, und mit denen ist es einfacher, Daten aufzurufen, zu filtern und sortieren bevor man sie anwendet. Auch in der Datenbankwelt gibt es einen Ruck in Richtung einfacherer und schnellerer Lösungen. Der Beiweis sind eine ganze Menge NoSQL Umgebungen, die derzeit ausgetestet werden. Diese werden jetzt auch im Web und nativ in Browsern behandelt. Ian Hickson von Google schlug die Web SQL database vor und Nikunj Mehta, Jonas Sicking (Mozilla), Eliot Graff (Microsoft) and Andrei Popescu (Google) gehen einen Schritt weiter und schlagen eine schon indizierte Datenbank mit Indexed DB als Alternative vor.

In der Mobilwelt ist ein sehr wichtiges Thema, Daten anzubieten, wenn es keine Verbindung gibt, und die Offline Webapps API ist eine standardisierte Lösung für dieses Problem.

Wie schon am Anfang gesagt, wir haben eine interessante Zeit vor uns. Lasst uns das Internet schneller, einfacher und vor allem zuverlässiger gestalten, indem wir all die neuen Sachen verwenden, die uns Browser anbieten. Alles zum Thema HTML5 und localStorage gibt es in dem Kapitel von »Dive into HTML5« auf Englisch.

Gemälde (Ausschnitt): Antoine Watteau, Das Ladenschild des Kunsthändlers Gersaint, 1720/21. Schloss Charlottenburg, Berlin.

Anmerkung der Redaktion

Logo: 24 ways - to impress your friends

Dieser Artikel ist die deutsche Übersetzung von Christians Beitrag für die Seite 24ways. Dieser Adventskalender bietet noch viele weitere interessante Beiträge, alle in englischer Sprache.

Kommentare

Mathias Nater
am 06.12.2010 - 12:09

Danke für den ausführlichen Artikel.

Ich glaube noch ergänzen zu müssen, dass if(('localStorage' in window) && window['localStorage'] !== null) nicht ausreicht, wenn im Firefox die Storage-Funktion per about:config ausgeschaltet ist; er meldet dann einen Security error" code: "1000 und bricht das Script ab.

Es braucht also zusätzlich ein try{}-catch(e){}

Gruss,
Mathias

PS: ich setze DOM-Storage ziemlich erfolgreich zur Zwischenspeicherung der Trennmuster in Hyphenator.js ein.

Permanenter Link

gung
am 06.12.2010 - 14:03

Hi,
every time codepo8 speeks YQL ain't far away, cool... I love it. Nice calender, great idea for us KRAUTS. Looking forward the next days. Have a nice day. cu

Permanenter Link

Michael
am 06.12.2010 - 14:16

Ein wirklich interessanter Beitrag zum Thema. Vor gar nicht all zu langer Zeit haben David Maciejewski und Jan Tißler in TechnikLOAD #13 darüber berichtet und eine wirklich interessante HTML5 Slideshow vorgestellt. Auch Beispiele wie HTML5-eBooks mit Lesezeichen etc. kommen in dem Beitrag vor.

Grundsätzlich wird die Möglichkeit der Datenspeicherung einen großen Teil dieser HTML5-Revolution ausmachen. Gerade SaaS wird dadurch einen weiteren Aufschwung erleben.

Permanenter Link

Die Kommentare sind geschlossen.