PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


HTML 5 und Javascript 5: Clientseitige Datenbanken

with 11 comments

Nachdem sich die Web Hypertext Application Technology Working Group (WHATWG) 2004 gegründet hat, die aus einigen bedeutenden Internet-Riesen besteht (u.a. Apple, Mozilla, Opera), kommt wieder Fahrt in neue HTML- und Javascript-Standards. Die Gruppe hat viele Proposals erstellt, von denen jetzt einige vom W3C übernommen werden. Stichworte sind da HTML 5, ECMAScript 5, Web Workers, Web Storage, Web Sockets und einiges mehr.

Zu den Web Workern hatte ich ja bereits etwas geschrieben.

Web Sockets wird die Pushing-Technik werden, mit der Server bei Änderungen Nachrichten an den Browser schicken können, dann erübrigt sich das derzeitige Pullen und Nachfragen via AJAX, ob es Neuigkeiten gibt. Das entlastet die Server und spart Traffic, und Nachrichten kommen genau dann im Browser an wenn sie auf dem Server passieren, nicht erst beim nächsten Pull.

Heute soll es um den Web Storage gehen, die clientseitige Datenbank im Browser. In der Vergangenheit konnte man Daten nur auf der aktuellen Seite in Javascript-Variablen vorhalten, sobald aber der nächste Full-Page-Reload kommt sind die Daten futsch. Die zweite Möglichkeit waren Cookies, in denen man Daten speichern kann. Da aber Cookies bei jedem Request mitgesendet werden, ist das kein guter Speicherort für größere Datenmengen, Cookies sollte man höchstens für eine SessionID nutzen.

HTML 5 bietet uns die Möglichkeit, mittels des localStorage einfache Daten im Client zu speichern. Hier ein kleines Beispiel:

<!DOCTYPE html>
<html>
<head>
	<script type="text/javascript">
	function store() {
        var key = document.getElementById('key').value;
        var data = document.getElementById('data').value;
        localStorage.setItem(key, data);
      }
     function read() {
       var key = document.getElementById('key').value;
       document.getElementById('data').value = localStorage.getItem(key);
     }
	</script>
</head>
<body>
	<textarea id="data"></textarea>
	<p>
		<label>key: <input id="key"></label>
		<input type="button" value="Read" onclick="read()">
		<input type="button" value="Store" onclick="store()">
	</p>
</body>
</html>

Dieser Code funktioniert bereits im IE 8, Firefox 3.5, Safari 4. Auch wenn man zwischendurch wegsurft und dann wiederkommt sind die Daten noch auslesbar. Wenn man allerdings 2 Fenster öffnet und in beiden Fenstern den selben Key speichert, überschreibt man den jeweils anderen Wert. Um das zu vermeiden (also beide Fenster zu trennen) gibt es den sessionStorage. Wenn man im obigen Code den localStorage durch den sessionStorage austauscht, kommen sich die beiden Fenster nicht mehr in die Quere, allerdings sind die Daten futsch wenn man den Tab schliesst. Für eine permanente Speicherung, auf die alle Tabs zugreifen können, nutzt man also den localStorage.

Bei diesem Feature handelt es sich allerdings „nur“ um einen einfachen Key-Value-Store, wir können keine komplexen Abfragen oder ähnliches erstellen.

In Google Gears wurde es bereits vorgemacht: Idealerweise brauchen wir eine clientseitige Datenbank, die wir via SQL füllen und abfragen können, um Daten auf den Client auszulagern und so den Server zu entlasten und Daten nicht bei jedem neuen Besuch neu laden zu müssen. Stattdessen werden Daten, die einmal den Client erreicht haben, in die Datenbank gelegt, die dann auch sehr schnell ausgelesen, sortiert und gruppiert werden können, also eine vollwertige Datenbank im Browser.

Mit ECMA-Script 5 (im Volksmund Javascript 5) wird das möglich sein. Der folgende Code funkioniert aktuell nur in WebKit/Safari, für Firefox und Chrome gibt es aber bereits funktionierende Beta-Implementierungen:

<!DOCTYPE html>
<html>
<head>
	<script type="text/javascript">
	if (!window.openDatabase) {
		alert( "Browser does not support database storage.");
	} else {
		db = openDatabase('testDb', '1.0', 'testDb', 65536);
	}

	function create() {
	    db.transaction(
	        function (tx) {
	            tx.executeSql('CREATE TABLE todo (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, description TEXT NOT NULL DEFAULT "", todo_order INTEGER NOT NULL DEFAULT 0, done INTEGER NOT NULL DEFAULT 0 );',
					[], function (tx, result1) {
						alert("successfully created database");
					}, errorHandler
				);
	        }
	    );
	}

	function insert() {
		db.transaction(
			function(tx) {
				tx.executeSql('INSERT into todo (description, todo_order) VALUES ( ? , ? );',
					[ document.getElementById('firstKey').value , 3 ],
					function (tx, resultSet) {
						if (!resultSet.rowsAffected) {
							// Previous insert failed. Bail.
							alert('No rows affected!');
							return false;
						}
						alert('insert ID was '+resultSet.insertId);
					}, errorHandler
				);
			}
		);
	}

	function selectnow() {
		db.transaction(
			function(tx) {
				tx.executeSql('SELECT description FROM todo WHERE done=0', [], function(tx, results) {
					// do some more stuff
					console.log("Results returned: "+results.rows.length);
					var resultString = '';
					for (var i=0; i<results.rows.length; i++) {
						var row = results.rows.item(i);
						resultString += row['description'] + '<br/>';
					}
					document.getElementById('latestUpdated').innerHTML = resultString;
					alert("My first database query finished executing!");
				}, errorHandler);
			}
		);
	}

	function drop() {
		db.transaction(
			function(tx) {
				tx.executeSql('DROP Table todo', [], function(tx, result1) {
					alert("successfully deleted database!");
				}, errorHandler);
			}
		);

	}

	function errorHandler(transaction, error)
	{
	    // error.message is a human-readable string.
	    // error.code is a numeric error code
	    alert('Oops.  Error was '+error.message+' (Code '+error.code+')');
	}
	</script>
</head>
<body>
	<h3>Create Table</h3>
	<input type="button" name="create" value="Create" onclick="create()"/>
	<h3>Insert Values</h3>
	<input type="text" id="firstKey" value="firstValue"/>
	<input type="button" name="insert" value="Insert" onclick="insert()"/>
	<h3>Select Values</h3>
	<input type="button" name="select" value="Select now" onclick="selectnow()"/>
	<br/>
	<span id="latestUpdated"></span>
	<h3>Drop Table</h3>
	<input type="button" name="drop" value="Drop" onclick="drop()"/>
</body>
</html>

Im Safari sieht das dann so aus:

Eine sehr gute Quelle zu diesem Thema ist diese Seite bei Apple über die Javascript Database.

Weitere Interessante Features von HTML 5 und ECMA-Script 5: Strict Mode, getter und setter bei Objekten, Objekte „einfrieren“, neue Html-Tags, neue Drag&Drop Funktionen, postMessage() und vieles mehr.

Einiges davon funktioniert bereits im Firefox 3.5, Chrome, Safari und auch im IE8. Beispielsweise:

<!DOCTYPE html>
<html>
<head></head>
<body>
	<video src="testvideo.mp4" controls autobuffer autoplay></video>
</body>
</html>

Auch YouTube hat bereits eine HTML 5 Beta-Seite gestartet

Ich werde in den nächsten Wochen einige der Dinge vorstellen, die wir erwarten können und uns das Leben etwas einfacher machen werden.

Written by Michael Kliewe

Januar 6th, 2010 at 7:53 am

11 Responses to 'HTML 5 und Javascript 5: Clientseitige Datenbanken'

Subscribe to comments with RSS or TrackBack to 'HTML 5 und Javascript 5: Clientseitige Datenbanken'.

  1. Ich will mal dazu noch was loswerden. Ich finde es super, dass HTML5 solche neue Möglichkeiten bietet und die Entwicklung dort voran schreitet um das zukünftige Entwicklen zu erleichtern.

    Leider ist es zurzeit aber eine reinste Mehrarbeit, da man im beruflichen Umfeld an der Unterstützung vom IE6 kaum vorbeikommt. Und selbst im IE7 und IE8 wird vieles nicht unterstützt. Somit kann man doch HTML5-Feature browserübergreifend sicherlich nicht vor 2015 nutzen. Wieso sich dann jetzt damit beschäftigen?

    Ulf

    12 Jan 10 at 08:22

  2. Du fragst wieso? Ich frage wieso nicht? Je früher du damit anfängst um so besser.

    Ich weiß nicht wie lange du im Web arbeitest, aber es gibt keinen Tag X wo dann gestartet wird. Die breite Masse trägt zum etablieren eines Standards bei. Je früher du rudimentär Neuerungen einsetzt – eventuell mit Fallbacks – kannst du mit dazu beitragen das sich ein Standard etabliert.

    Das Web war zu keiner Zeit ein starrer Standard.

    Christian

    12 Jan 10 at 10:51

  3. Ganz viel schöner hätt ich es auch nicht sagen können 😉
    Des weiteren spart es eben auch Traffic, CPU-Zeit und erhöht die User-Experience.
    Schau dir zB irgendein soziales Netzwerk an. Dort hat man ja meistens auch eine Nachrichten-Funktion. Wenn man also einmal in seine Nachrichtenbox reingeschaut hat, werden alle vorhandenen Nachrichten im Browser angezeigt und können dort in einer Datenbank gespeichert werden. Beim nächsten Klick oder den nächsten Besuchen brauchen all diese Nachrichten nun nicht nochmals übertragen werden, sie werden einfach aus der clientseitigen Datenbank genommen.

    Je größer diese Informationen werden, desto mehr Traffic spart der Anbieter, und gerade Leute mit langsamen Internetverbindungen sehen die Seite einfach viel schneller, da nur noch ein Bruchteil neu übertragen werden muss. Gepaart mit AJAX sind da echt tolle Sachen möglich.
    Für eine kleine 0815-Seite ist diese Datenbank natürlich nicht so interessant.

    Leider sind diese Datenbanken größenbeschränkt, zB bietet der Safari aktuell 5 MB Datenbank pro Domain. Aber für viele Dinge reicht das aus.

    Michael Kliewe

    12 Jan 10 at 11:31

  4. Mal ganz davon ab, zieht das ie6 Argument bei mir sowieso nicht mehr. Ich habe gestern erst fast 8Std. damit zubringen müssen eine Seite nur vom Styling her irgendwie erträglich zu machen. IE6 wird früher oder später sterben, da der Support jetzt bis 2015 verlängert wurde heißt das nicht das ich neue Technologien nicht ausprobiere und einsetze.

    Die Antwort heißt schlicht weg: „Fallback“. Kostet mehr Arbeit und Zeit aber das muss dann mit dem Kunden kommuniziert werden. Die Grätsche müssen wir als Web-Devs halt noch machen.

    Da ich selbst überzeugter Cloud-Computing-Evangelist bin kann ich dir nur raten so früh wie nur möglich mit neuen Webtechnologien auseinanderzusetzen.

    Ganz nebenbei hat der IE als gesamt Packt letztes Jahr 10% an Verbreitung verloren, zu Recht!

    „If you look around at browsers, you’ll find that most of them support scalable vector graphics,“ Berners-Lee said. „I’ll let you figure out which one has been slow in supporting SVG.“

    Die Rede war hier vom IE und zwar nicht vom IE6 😉 nur soviel zu dem Thema 🙂

    Christian

    12 Jan 10 at 11:50

  5. Das Argument der Mehrarbeit und Kosten ist für mich noch nicht wirklich entkräftigt. Wenn ich einen Kunde erzähle, dass er x (nur Fallsbacks) oder x+y (mit neuen HTML5-Features und Fallbacks) zahlen kann, dann schlägt doch in der heutigen Geschäftswelt alles.

    Und sicherlich kann er zur Adaption eines Standars beitragen wenn ich es selbst einsetze, aber Microsoft ändert damit auch nicht seine Adaptionsrate und Firmenpolitik. Der IE6 wird weiterhin bis 2015 unterstützt. Ich empfinde das als Schlag ins Gesicht und dem IE muss man sich eben unterwerfen wenn man professionell entwickelt (bei privaten Projekten kann man ja andere Entscheidungen treffen).

    Ulf

    13 Jan 10 at 14:43

  6. Zu dem „Wieso“: Mobile Safari unterstützt das Feature ebenfalls. Somit lassen sich für iPhone / iPod touch Web-Applikationen erstellen, die auch offline nutzbar sind.

    Zusammen mit Javascript-Bibliotheken wie iui oder jqTouch kann man dann ohne sich in Objective-C einarbeiten zu müssen(!), iPhone Anwendungen entwickeln, die beinahe wie Apps aussehen.

    Ich find das gut.

    till

    12 Apr 10 at 01:48

  7. Hallo!

    Ich finde speziell den Artikel hier sehr informativ! Schön, dass sich jemand die Mühe macht! Ich bin jetzt schon ganz aufgeregt am Wochenende eine lange Zeit aufgeschobene Portierung einer MS-Access/VBA-Applikation(ich trau mich es gar nicht zu schreiben) zu beginnen 🙂
    Super!

    Grüße

    Christian

    5 Aug 10 at 10:20

  8. […] […]

  9. Hallo,

    ich hab mal eine Frage. Die selectnow() Funktion habe ich versucht für meine Zwecke umzubauen. Eigentlich möchte ich nur, dass die Funktion als return-Wert die Anzahl der gefundenen Zeilen (results.rows.length) des inneren selects nach „draußen“ zurück gibt. Nur gelingt es mir nicht den Wert irgendwie aus diesem function(tx) { tx.executeSql … } herauszubekommen.

    Für einen konkreten Beispielcode wäre ich sehr dankbar!

    Gruß,
    Marcus

    Marcus

    26 Apr 12 at 11:16

  10. […] […]

  11. […] HTML 5 und Javascript 5: Clientseitige Datenbanken […]

Leave a Reply

You can add images to your comment by clicking here.