Ein erweiterbarer Wrapper für DOM Storage aus HTML 5, Microsofts userData, Session-Cookies sowie Fensternamen unter Verwendung von JSON zur Datenserialisierung
Heutige dynamische Webanwendungen verlagern zunehmend Logik auf den Client, d.h. in den Webbrowser, wo komplexe JavaScript-Anwendungen laufen. Diese können im Hintergrund mit dem Webserver Daten austauschen – das entsprechende Interface-Konzept wurde unter dem Schlagwort Ajax populär. Auf die Spitze getrieben wird es durch sogenannte Single Page Applications. Der Websurfer navigiert nicht mehr über Links durch verschiedene HTML-Dokumente, die nach und nach vom Server abgerufen werden, sondern ein einziges HTML-Dokument dient als Grundlage für eine umfangreiche JavaScript-Anwendung, die das Abrufen der notwendigen Daten sowie das Übermitteln von Eingaben jeweils selbst übernimmt.
Das hier vorgestellte Script zielt allerdings auf solche Webanwendungen, die das klassische Konzept von mehreren HTML-Dokumenten noch nicht gänzlich hinter sich gelassen haben, aber bereits stark mit clientseitigen Scripten aufgewertet sind. Die Aufgabenstellung ist nämlich der Austausch von Javascript-Daten zwischen zwei Dokumenten. Ein möglicher Anwendungsfall ist die clientseitige Speicherung von Session-Daten, die nicht mit jeder Anfrage an den Server gesendet werden müssen, wie es bei klassischen Session-Cookies der Fall ist.
Verbreitete Lösungen für den besagten Austausch sind:
window
-Objekte über die Objekte parent
und frames
(siehe Fenster- und Frameszugriff)Nur in einem Frameset werden mehrere Dokumente zur gleichen Zeit parallel angezeigt. Scripte in diesen Dokumenten haben direkten Zugriff auf die obersten window
-Objekte der jeweils anderen Frames sowie deren Unterobjekte.
Sollen zwei Dokumente nacheinander anstatt gleichzeitig angezeigt werden, so wäre ein Spiel »über Bande« möglich: Ein Frameset mit nur einem Frame. Die Scripte zweier im Frameset angezeigten Dokumente haben Zugriff auf das dritte Frameset-Dokument mit eigenen window
-Objekt, das beim Dokumentwechsel bestehen bleibt und das als »Flaschenpost« zur Weitergabe genutzt werden kann. Dasselbe gilt beim Einsatz von eingebetteten Frames (iframe
- oder object
-Element).
Frames erlauben zwar den direkten JavaScript-Zugriff auf Objekte eines anderen Dokuments, aber nur äußerst selten bringt eine Website diese Konfiguration bereits mit sich. Frames und eingebettete Frames bringen zahlreiche Nachteile mit sich und es wird nicht empfohlen, sie ausschließlich zur JavaScript-Datenübergabe einzusetzen.
Die Alternativtechniken ermöglichen keinen unmittelbaren Zugriff und machen eine mittelbare Übertragung der Daten notwendig. Das Schema dafür lautet:
Sender (Ursprungsdokument) → Kodierung → Kanal → Dekodierung → Empfänger (Zieldokument)
Die genannten »Kanäle« erlauben nicht den Austausch von beliebigen JavaScript-Objekten, sie bringen bestimmte Einschränkungen mit sich. Den Kanal können Sie sich als Nadelöhr vorstellen, durch das nur die Informationen durchpassen, die korrekt und passend kodiert sind.
Konkret bedeutet das: In Cookies, im Fensternamen und in der URI können letztlich nur Strings gespeichert und ausgelesen werden. Solange nur einzelne JavaScript-Strings wie "Hallo Welt!"
oder Zahlen wie 168732.12
übertragen werden sollen, ist das kein Problem. Wenn jedoch eine komplexe Datenstruktur wie beispielsweise ein Array übertragen werden soll, ist eine Serialisierung, also Umwandlung in einen String nötig. Das empfangende Dokument muss diesen String schließlich dekodieren, also zurück in ein Array-Objekt umwandeln, damit es dem Script dort in gleicher Weise zur Verfügung steht.
window.name
Cookies haben den Nachteil, dass ein Cookie üblicherweise nur 4096 Bytes (4 KB) an Daten enthalten kann. Da die Datenmenge durch die Serialisierung und spezielle Kodierung mitunter doppelt so groß werden kann, ist dieses Limit schneller erreicht, als man vermuten würde.
Für den Fensternamen haben die Browser keine rigide Limitierung vorgesehen. Der Fenstername kann praktisch alle möglichen Zeichen beinhalten und selbst große Datenmengen von mehreren 100 Kilobyte werden erfolgreich verarbeitet. Allerdings funktioniert window.name
ganz anders und bringt entsprechende Probleme mit sich: Der Fenstername bleibt solange bestehen, wie das Browserfenster (bzw. der Browser-Tab) bestehen bleibt.
Das heißt, der Name kann von jedem Dokument ausgelesen werden, welches nach dem Setzen des Namens im gleichen Fenster geladen wird. Das wichtige Sicherheitskonzept der Same-Origin-Policy verhindert den Zugriff auf Dokumente und Cookies von fremden Domains. Der Fenstername unterliegt nicht dieser Beschränkung. Das bedeutet, dass die gespeicherten Daten von allen Dokumenten auf allen Domains ausgelesen werden können, nicht nur von Dokumenten, die von derselben Domain stammen. Es ist auch nicht zuverlässig möglich, window.name
beim Verlassen einer Domain automatisch zu löschen, sodass die Daten anderen Websites nicht zur Verfügung stehen.
window.name
eignet sich in Verbindung mit Frames dafür, Daten kontrolliert und gezielt zwischen verschiedenen JavaScript-Domains zu übertragen. Für den Zweck der Speicherung von Session-Daten ist der Fenstername hingegen als unsicher zu betrachten! Sie sollten darin niemals sicherheitsrelevante, vertrauliche oder gar direkt personenbezogene Daten speichern – dazu gehören etwa die Session-ID, mit der sich der Webbrowser des Benutzers sich gegenüber der serverseitigen Anwendung nach der Anmeldung authentifiziert. Ansonsten sind im schlimmsten Fall Session Hijacking und Identitätsdiebstahl Tür und Tor geöffnet. Verwenden Sie window.name
im öffentlichen Web daher nur zur Übergabe von »harmlosen« Daten.
Um die JavaScript-Datenübergabe zwischen Dokumenten zu vereinfachen, definiert der entstehende HTML-5-Standard eine Technik namens DOM Storage. Dieser erlaubt es, String-Daten an einem zentralen Objekt namens window.sessionStorage zu speichern, indem man eine Eigenschaften dessen anlegt. Dazu reicht eine einfache Wertzuweisung. Wollen wir einen Wert unter einem Namen speichern, so schreiben wir:
window.sessionStorage.nachricht = "Hallo! Ich bin ein übergebener Text!";
Die Angabe von window.
vor dem sessionStorage
ist nicht zwingend notwendig, da es sich um ein Objekt im globalen Gültigkeitsbereich handelt. Der Eindeutigkeit halber geben wir window
immer an, um auf diesen Umstand hinzuweisen.
Dieser sessionStorage
hat dieselbe Haltbarkeit wie ein Session-Cookie und steht allen Dokumenten der Domain zur Verfügung. In einem Folgedokument können wir den gespeicherten Wert ganz auslesen, indem wir das zuvor angelegte Unterobjekt von sessionStorage
ansprechen:
window.alert(sessionStorage.nachricht);
Auch im sessionStorage können letztlich nur Strings gespeichert und ausgelesen werden. Komplexe Datenstrukturen bedürfen wie auch bei den bereits diskutierten Techniken einer Serialisierung und schließlich seitens des empfangenden Dokuments einer Dekodierung.
DOM Storage steht derzeit (Januar 2009) im Firefox ab Version 2 zur Verfügung. Der kommende Internet Explorer 8 wird ebenfalls DOM Storage unterstützen (Microsoft-Dokumentation), wie bereits die erste Beta-Version aus dem März 2008 demonstriert. Es ist damit zu rechnen, dass auch die anderen großen Browser-Engines (Safari/Webkit und Opera/Presto) bald nachziehen werden.
DOM Storage ist die leistungsfähigste, sicherste und einfache Technik zur Übertragung von JavaScript-Daten zwischen mehreren Dokumenten. Da noch nicht alle Browser den kommenden Standard unterstützen, müssen wir auf Alternativtechniken zurückgreifen, falls sessionStorage
nicht zur Verfügung steht. Dabei soll die leistungsfähigste verfügbare Technik verwendet werden.
Eine weitere mächtige Übertragungstechnik heißt userData und gehört zu den sogenannten DHTML-Behaviours. Das sind allesamt Microsoft-proprietäre Erfindungen, also Zusätze, die ausschließlich im Internet Explorer funktionieren.
Das ist jedoch kein Grund, sie gar nicht zu verwenden. Wir können sie bedenkenlos verwenden, wenn der Anwender die Website mit einem Internet Explorer besucht und die verwendete Browser-Version noch keine besseren, standardisierten Techniken wie DOM Storage unterstützt.
UserData ist ein »Verhalten«, dass man einem beliebigen Element im Dokument geben kann. Das Element bekommt dadurch gewisse mit JavaScript ansprechbare Fähigkeiten. Im Falle von userData bietet das Element eine Schnittstelle zu einem zunächst leeren XML-Dokument, das das Script beliebig füllen kann. Dieses XML-Dokument nutzen wir als Ablage für die Datenübertragung.
Wir können das XML-Dokument wie gewohnt über das Kern-DOM ändern und darin strukturierte Daten in selbst erzeugten Elementen, Attributen und Textknoten speichern. Deren Aufbau können wir selbst bestimmen, denn für das Dokument gibt es keinen festgelegte Regeln. Das XML-Dokument wird schließlich unter einem Namen gespeichert – der Internet Explorer wird es daraufhin als .xml
-Datei auf die Festplatte des Websurfers schreiben.
In einem Folgedokument bekommt ebenfalls ein Element das userData-Verhalten zugewiesen. Daraufhin kann man das zuvor angelegte und gespeicherte XML unter dem selben Namen laden. Somit kann man wieder über das DOM auf die darin abgelegten Daten zugreifen.
UserData bietet uns nennenswerte Vorteile im Vergleich zu Cookies und window.name
: Wir können je nach Sicherheitszone des Internet Explorers zwischen 64 und 512 KB speichern. In der Internetzone kann ein HTML-Dokument XML-Dokumente im Umfang von insgesamt 128 KB speichern, alle HTML-Dokument einer Domain XML-Dokumente im Gesamtumfang von 1024 KB. Außerdem müssen wir nicht streng auf die Kodierung der Daten achten, wie es bei Cookies nötig ist. Denn in Textknoten und Attributwerte eines XML-Dokuments können wir alle möglichen Zeichen via JavaScript/DOM einfügen, ohne dass es gefährlich wird.
Alle besprochenen Techniken zur indirekten Übertragung erfordern eine Serialisierung, da deren Übertragungskanäle nur Strings zulassen. Zudem erfordern einige Techniken wie Cookies eine zusätzliche, aufwändige Kodierung, weil gewisse Zeichen im String nicht enthalten sein dürfen und maskiert, d.h. durch andere ersetzt und somit »entschärft« werden müssen.
Zur Serialisierung wurden in der Vergangenheit verschiedene Verfahren benutzt, die manche JavaScript-Daten übertragen konnten, andere aber nicht oder nicht zuverlässig. Dabei existiert ein De-facto-Standard, mit dem sich vielfältige strukturierte Daten zuverlässig serialisieren lassen: die JavaScript Object Notation (JSON). JSON hat mittlerweile auch jenseits von JavaScript Verbreitung gefunden und ist das Format der Wahl, wenn man einem JavaScript strukturierte Daten zur Verfügung stellen will.
Für die Serialisierung von Daten in einen String im JSON-Format und die Zurückwandlung dieses Strings in JavaScript-Daten wird das Helferscript json2.js von Douglas Crockford verwendet, siehe JSON in JavaScript. Es bietet die zwei JavaScript-Funktionen JSON.stringify
und JSON.parse
an.
Der große Clou bei der Wahl von JSON als Übertragungsformat ist folgender: Neuere Browser haben die genannten Funktionen JSON.stringify
und JSON.parse
bereits »serienmäßig« eingebaut. Man muss in diesem Fall kein zusätzliches JavaScript laden, das die Funktionalität bereitstellt. Der Vorteil dieser sogenannten »nativen« Umsetzung ist vor allem Zuverlässigkeit und Geschwindigkeit. Auch an dieser Stelle machen wir von den neuen Möglichkeiten der Browser Gebrauch. Wenn diese noch nicht verfügbar sind, laden wir automatisch das benötigte Script nach.
JSON als Programmiersprachen-übergreifendes, textbasiertes Datenformat ist zu unterscheiden von Objekt-Literalen in JavaScript (ECMAScript).
JSON kann folgende JavaScript-Datenstrukturen direkt ausdrücken:
null
Folgende Objekte lassen sich nicht (ohne weiteres) mittels JSON speichern und übertragen:
RegExp- und Date-Objekte sind nur dann übertragbar, wenn sie vorher manuell in einen String umgewandelt werden. Die Umwandlung von selbst definierten Funktionen in Strings unterstützen ebenfalls die meisten Browser. In diesen Fällen müssen Sie selbst Hand anlegen, indem Sie die toString
-Methode aufrufen, um das Objekt zur Übertragung vorzubereiten:
var funktion = function () { alert("Hallo Welt!") ; }; // Umwandlung in einen String: var serialisierteFunktion = funktion.toString(); var regulärerAusdruck = /.+/gi; // Umwandlung in einen String: var serialisierterRegulärerAusdruck = regulärerAusdruck.toString(); var datum = new Date; // Umwandlung in einen String: var serialisiertesDatum = datum.toString();
Die Rückverwandlung des serialisierten Strings in das Ausgangsobjekt kann bei Funktionen und regulären Ausdrücken mit eval
erfolgen, bei dem Datumswert mit new Date
.
var funktion = eval(serialisierteFunktion); var regulärerAusdruck = eval(serialisierterRegulärerAusdruck); var datum = new Date(serialisiertesDatum);
Methode | Serialisierung | Kodierung | Größenlimitierung | Haltbarkeit | Sicherheit |
---|---|---|---|---|---|
HTML 5 DOM Storage (window.sessionStorage ) |
(hier) JSON | keine notwendig | X KB netto | Session (Beschränkung durch die Wahl von |
Same-Origin-Policy |
Microsoft userData Behaviour | (hier) JSON | keine notwendig | i.d.R. 128 KB brutto | Session (Beschränkung durch das Script, Session-übergreifende Speicherung wäre möglich) |
Same-Origin-Policy |
Cookies (document.cookie ) |
(hier) JSON | aufwändig und speicherhungrig | 4 KB brutto | Session (Beschränkung durch das Script, Session-übergreifende Speicherung wäre möglich) |
Same-Origin-Policy |
Fenstername (window.name ) |
(hier) JSON | keine notwendig | bis zu mehreren Megabyte | solange das Fenster bzw. der Tab geöffnet ist | keine |
Es gibt noch weitere und weitaus komplexere Techniken, die sich zur Übertragung von JavaScript-Daten zwischen Dokumenten eignen. Hier wurde allerdings der Fokus auf den einfachen Datenaustausch während einer Browser-Session gelegt. Wenn der Anwender den Browser schließt, werden die gespeicherten Daten bestenfalls automatisch gelöscht.
Andere Techniken widmen sich vornehmlich dem persistenten, d.h. dauerhaften und Session-übergreifenden Speichern von Daten auf dem Client. Das besagte userData
des Internet Explorers ist im Grunde für die dauerhafte Speicherung angelegt. Man kann die Haltbarkeit bzw. Lebensdauer der clientseitig gespeicherten Daten jedoch auf die Session begrenzen – davon macht das hier vorgestellte Script Gebrauch.
localStorage
aus HTML 5DOM Storage aus der HTML-5-Spezifikation umfasst neben dem bereits besprochenen Objekt sessionStorage
ein Äquivalent zur persistenten Speicherung. Das entsprechende Objekt heißt localStorage
und ist auf ähnliche Weise nutzbar:
localStorage.nachricht = "Dieser Text wird vom Browser " + "sessionübergreifend gespeichert. Die Website example.org sowie deren "+ "Unter-Domain können ihn auch nach einem Browser-Neustart noch auslesen.";
openDatabase
aus HTML 5HTML 5 definiert für die Speicherung zahlreicher gleichförmiger Datensätze eine JavaScript-Schnittstelle zu einer abgespeckten, im Browser integrierten SQL-Datenbank. Diese lässt sich ähnlich ansprechen wie »große« SQL-Datenbanken, die im Webkontext verbreitet sind (z.B. MySQL oder PostgreSQL): Mit CREATE TABLE
wird eine Tabelle in der Datenbank erzeugt und deren Einträge lassen sich mit den Befehlen SELECT
, INSERT
, UPDATE
und DELETE
auslesen und manipulieren. Dennoch ist der Befehlssatz im Vergleich zu richtigen relativen Datenbank-Managementsystemen sehr beschränkt und derzeit noch nicht fest spezifiziert.
Ab Flash 7 besteht die Möglichkeit, dass ein Flash-Film ActionScript-Daten dauerhaft als »Super-Cookie« auf dem Client speichern kann. Diese Technik nennt sich SharedObject
. Um JavaScript-Daten mittels Flash als SharedObject zu speichern, muss ein kleiner Flash-Film eingebundenen werden, der eine entsprechende Schnittstelle für JavaScript anbietet, mit dem sich via JavaScript ActionScript-Funktionen aufrufen lassen.
Das Script besteht intern aus einer Reihe verschiedener Umsetzungen (engl. Implementations). Diese nutzen jeweils eine der vorgestellten vier Techniken. Das Script soll automatisch die leistungsfähigste Umsetzung zur Datenübergabe verwenden, die der verwendete Browser bereitstellt. Nach außen hin soll das Script eine einheitliche Programmierschnittstelle (API) anbieten. Das Script dient somit als vereinheitlichende Abstraktion von den tatsächlichen unterschiedlichen Umsetzungen.
Jede der Umsetzungen wird als Objekt notiert, das einen gleichen Satz an Methoden anbietet, die auf gleiche Weise mit Parametern angesteuert werden können. Das sind vor allem die Methoden get
, add
und remove
zum Auslesen, Hinzufügen, Entfernen von gespeicherten Einträge und clear
zum Löschen aller gespeicherten Einträge.
Die Umsetzungen ähneln einander und weichen nur im Detail voneinander ab. Beispielsweise bedürfen die vier Techniken einer Serialisierung der Daten. Diese Logik wird nicht bei jeder Umsetzung wiederholet, sondern stattdessen wird eine Vorlage für die Umsetzungen eingesetzt (engl. Implementation Template bzw. Mixin). Wenn eine Umsetzung mit Serialisierung arbeiten muss, »erbt« sie einfach die allgemeinen Methoden von der Vorlage. Die spezifischen Methoden können dann sehr knapp notiert werden.
Der grobe Aufbau des Scriptes sieht wie folgt aus:
(function () { var publicInterfaceName = "ssw"; var helper = { … }; var serializers = { json : { … } }; var implementation = { … }; var mixins = { serialized: { … } }; implementation.add(mixins.serialized, { … }); … implementation.detect(); delete implementation; })();
Das gesamte Script ist in eine anonyme (namenlose) Funktion gekapselt. Diese wird sofort ausgeführt wird, nachdem sie notiert wurde. Auf diese Weise können wir lokale Variablen notieren, die zwar allen Funktionen innerhalb der Kapsel-Funktion zur Verfügung stehen, aber nicht globalen Gültigkeitsbereich (das window
-Objekt) »verschmutzen«.
Ziel des Scriptes ist es, ein global verfügbares Objekt zur Verfügung zu stellen, standardmäßig unter window.ssw
. Unter welchem globalen Namen das Objekt angelegt wird, ist durch eine Variable steuerbar. Der Bezeichner sollte möglichst eindeutig sein, um sich nicht mit JavaScript-Objekten zu überschneiden, die der Browser bereitstellt oder die von anderen Scripten angelegt werden.
Das Script definiert zuerst vier große Objekte, die weitere Objekte und Methoden gruppieren:
helper
serializers
(Unterobjekt: json
)init
, serialize
und unserialize
anbieten.implementation
mixins
(Unterobjekt: serialized
)Nachdem dieses Grundgerüst errichtet ist, wird die Liste mit den Umsetzungen (implementation.list
) gefüllt. Für die vier Umsetzungen wird jeweils die Methode implementation.add
aufgerufen. Als Parameter wird ein Objekt-Literal übergeben, der zumindest die Eigenschaft name
, die Methoden init
und isAvailable
sowie get
, add
, remove
, clear
bereitstellt.
Ein solches Umsetzungs-Objekt sieht schematisch folgendermaßen aus:
implementation.add({ name: "Name", /* Private Methoden */ init : function () { … }, isAvailable : function () { … }, /* Öffentliche Methoden */ get : function (name) { … }, add : function (name, value) { … }, remove : function (name) { … }, clear : function () { … } });
Die privaten Methoden finden nur intern Verwendung, die öffentlichen Methoden werden schließlich für die öffentliche Schnittstelle verwendet, sind also später unter window.ssw
verfügbar.
Bei der Verwendung einer Umsetzungsvorlage wird implementation.add
mit zwei Parametern aufgerufen. Der erste Parameter ist das Vorlagen-Objekt, der zweite Parameter das Umsetzungs-Objekt:
implementation.add(mixins.template, { name: "Name", /* necessary methods */ isAvailable: function () { … }, read: function () { … }, save: function (serializedString) { … } });
Das Umsetzungs-Objekt muss nur noch wenige spezifische Methoden anbieten, die restlichen werden vom Vorlagen-Objekt vererbt. Diese Vererbung ist in diesem Fall bloß ein Kopieren der Methoden (als Referenzen) vom Vorlagen-Objekt zum Umsetzungs-Objekt und wird auch Mixin bezeichnet.
Beim Einlesen des Scripts wird implementation.detect
ausgeführt, welches die automatische Auswahl der verfügbaren Umsetzung sowie deren Einrichtung vornimmt.
implementation.detect
durchläuft die Liste mit den Umsetzungen und ruft jeweils deren Methode isAvailable
auf. Diese Methoden prüfen, ob die benötigten Techniken zur Verfügung stehen, und geben true
oder false
zurück. Sobald eine unterstützte Umsetzung gefunden wird, bricht die Schleife ab und ruft implementation.setup
auf und übergibt das gefundene Umsetzungs-Objekt als Parameter. Wenn keine der Techniken unterstützt werden, bricht das Script einfach ab.
In implementation.setup
wird die gleich bleibende öffentliche Schnittstelle (engl. public interface) erzeugt, unter der das Script erreichbar sein wird. An dieses Objekt werden die öffentlichen Methoden (get
, add
, remove
, clear
) der gefundenen Umsetzung kopiert. Das entstehende Objekt wird schließlich als globale Variable unter window
abgespeichert, standardmäßig unter window.ssw
– der dabei verwendete Name kann wie gesagt eingestellt werden.
Das Script ist in Helferfunktionen (helper
), die Verwaltung der Umsetzungen (implementation
), die Vorlagen (mixins
), die Serialisierung (serializers
) und schließlich in die Umsetzungen geteilt. Der Sinn dieser Aufteilung ist die klare und geradlinige Programmierung, aber auch die Erweiterbarkeit und Modularisierbarkeit. Mit dieser Architektur sollen sowohl andere Umsetzungen, Vorlagen als auch Serialisierungstechniken möglich sein, die wahlweise auf die bereits definierten zurückgreifen können. Die zentralen Objekte mixins
und serializers
können um weitere Member erweitert werden. Neue Umsetzungen werden mittels Aufrufen von implementation.add
hinzugefügt.
add
Die Methode erwartet einen oder zwei Parameter und hat keinen Rückgabewert.
ssw.add("name", "wert") ssw.add("meinArray", [1, 2, 3, "Hallo"]);
ssw.add( { bla : "blub" } ) ssw.add( { meinArray : [1, 2, 3, "Hallo", { objekt : "mitString" }] } )
get
Die Methode kann mit keinem oder mit einem Parameter aufgerufen werden. Der Rückgabewert variiert entsprechend.
var speicherObj = ssw.get(); alert(speicherObj.name1 + " " + speicherObj.name2 + " " + speicherObj.name3);
var wert = ssw.get("name"); alert(wert);
remove
Die Methode erwartet den Namen vom Typ String als Parameter und hat keinen Rückgabewert.
ssw.remove("name");
clear
Die Methode erwartet keinen Parameter und hat keinen Rückgabewert.
ssw.clear();
forceImplementation
Setzt die automatische Erkennung und Wahl der Umsetzung außer Kraft und erzwingt die Verwendung der angegebenen Umsetzung. Dies kann beispielsweise zu Testzwecken sinnvoll sein.
Die Methode erwartet den Namen einer Umsetzung als String. Derzeit sind folgende Umsetzungen verfügbar:
"domstorage"
"userdata"
"cookie"
"windowname"
ssw.forceImplementation("cookie")
Autor: Mathias Schäfer, zapperlott@gmail.com
Lizenz: Public Domain (gemeinfrei)