Tipps und Tricks zu den Themen: Software- und Webentwicklung

Donnerstag, 19. Juni 2014

JCache - "Performance Addon for JavaScript and jQuery"

JCache ist ein kleines Addon (ca. 1Kb gzipped) und kann Selektor-Anweisungen auf das DOM oder per jQuery um das 1250-fache und mehr beschleunigen. Ermöglicht wird dieser Performance-Gewinn durch eine Zwischenspeicherung der jQuery-Selektoren. Der Zwischenspeicher wirkt auf alle Funktionen, so dass bei Erzeugung eines jQuery-Objektes oder setzen eines Styles zuerst im kompletten Speicher geschaut wird, ob ein entsprechendes Objekt vorhanden ist.

Update 02.08.2014: Die Weiterentwicklung des TurboCache Plugin heißt JCache

Wir haben das alte "Modular Pattern Design" in "Prototype" übertragen und ein paar Optimierungen vorgenommen. Der Code läuft unter Google-V8 jetzt ca. 60 mal schneller als in der alten Version. Damit können Selektor-Queries bis um das 1250-fache beschleunigt werden.





Das Addon ist 100% kompatibel mit allen jQuery-Versionen und kann auch ohne betrieben werden (Stand-alone). Es treten soweit keine Konflikte mit jQuery-Biliotheken auf.

Schnelleinstieg: 1. Installation
Schnelleinstieg: 2. Verwendung

Der TurboCache wird bei einem jQuery-Selektor auf einfachste Weise aktiviert.
Es wird anstelle von $(...) einfach nur ein $ vorangestellt: $$(...)
Anstelle von document.getElementById(...); diese Kurzschreibweise: _ID(...);


Source-Code: "JCache - Performance Plugin for JavaScript and jQuery" v1.2
Download jcache.js (Source)
Download jcache_min.js (Minified) (946 bytes gzipped)


Hinweise zur Verwendung

  • Alle Selektoren, die auf Elemente zeigen, die sich selbst nicht entfernen und neu erzeugen, können zwischengespeichert werden:
    • $$('#id')
    • $$('#wrapper, #menu, #content')
    • $$('#menu').find('a.class')
    • $$('a.class #menu')
  • Achtung: Selektoren die auf Inhalte zeigen, welche im Seitenprozess neu erstellt werden sollen, sollten nicht zwischengespeichert werden. Andernfalls wird die hinterlegte Referenzierung im Falle einer Änderung nicht mitgeändert und zeigt dann auf ein nicht mehr vorhandenes bzw. falsches Element. Eine Serialisierung des Objectes ist aktuell keine Option, da dieser Prozess wesentlich mehr Zeit in an Anspruch nimmt als das Element aus dem DOM neu auszulesen. Optimalerweise wird der Cache für Element eingesetzt, die fortwährend auf der Seite bleiben.
    • z.B. Selektoren die innerhalb eines Containers zeigen, dessen Inhalte dynamisch gesetzt werden
    • dies betrifft auch Elemente mit id-Attribut, sofern diese während der Laufzeit neu generiert werden
    • wir wollen demnächst einen Validator nachrüsten, der die Objekte entsprechend serialisiert
    • als alternative Cache-Verwaltung können die integrierten Hilfsfunktionen verwendet werden (siehe unten)
  • Anstelle von:
    • $$(window)
    • $$(document)
    • $$(document.body)
    sollten unbedingt diese Shortcuts verwenden:
    • $window
    • $document
    • $body
  • Sollte vermieden werden: $$(this)
  • es gibt folgende öffentliche Hilfsfunktionen zum steuern des Cache:
    • VOID removeCache();
    • ARRAY setCache(cache, [selector = all]);
    • ARRAY getCache([selector = all]);
    • BOOLEAN isCached(selector);


Profiler-Test: Leistungs-Vergleich

  1. Standard-Anweisung (DOM): getElementById('id')
  2. TurboCache (DOM): _ID('id')
  3. Standard-Anweisung (jQuery): $('#id')
  4. TurboCache (jQuery): $$('#id')
  5. TurboCache "PreTest": nur für Testzwecke (siehe 11.)
  6. TurboCache "DOM": $(document.getElementById('id'))
  7. Multiple Selektoren (jQuery): $('#id, #id, #id, ...')
  8. TurboCache (jQuery): $$('#id, #id, #id, ...')
  9. Standard-Anweisung (jQuery): $(document)
  10. TurboCache (jQuery): $$(document)
  11. TurboCache "PreTest": $$(document) (siehe 5.)
  12. TurboCache (PreCache): $document


Demnächst: Weitere Performance Features

Es sind weitere Features geplant, die wir an dieser Stelle ergänzen werden.
  • optimierter Selektor-Cache für Klassen und Elementtypen
  • Cache-Gültigkeitsüberprüfung für dynamische Inhalte (Objekt-Serialisierung und -validierung)
  • weitere Optimierungen für $.css() und $.animate()
  • TurboCache als Build-In-Feature


Changelog

  • v1.11 Fix: checks for compatible css attributes and fall back
  • v1.10 NEW: _CSS(selector [, css [, val]]) DOM-optimized CSS
  • v1.04 Fix: removeCache(selector) = null
  • v1.04 Fix: CACHE[selector] = CACHE['$#'+selector] = CACHE['#'+selector] = null
  • v1.03 NEW: $ID(STRING selector | ARRAY selector) ID-optimized query
  • v1.03 Fix: key = '$' + selector + ' ' + context
  • v1.02 NEW: $$(selector [, context]) contextual query
  • v1.02 Fix: setCache(_cache [, index])
  • v1.01 Fix: removeCache(selector) = false



Mittwoch, 11. Juni 2014

Mögliche Datenschutzkonflikte durch die Einbindung von Facebook, Twitter & Co, Google Analytics sowie bei Gebrauch von Cookies

Seit knapp 20 Jahren (seit Einführung des Internet Explorer 2, 1995) setzen Webentwickler Cookies ein. Der Großteil aller heutigen Internetshops benötigen Cookies, da diese bisher eine zuverlässige Technologie waren. Nicht so für Deutschland. Das Thema "Automatisierte Speicherprozesse" könnte schon bald ein Problem werden und genügend Munition für die nächste Abmahn-Weltmeisterschaft bieten. Mehr dazu in diesem Beitrag.

Durch aktuelle Geschehnisse zum Thema Datenschutz wird über den Einsatz von Cookies, vor allem Tracking-Cookies, sowie die direkte Einbindung von sozialen Plugins wieder fleißig diskutiert. Wir haben die kritisierten Problemstellen gesammelt und zu jedem Lösungsvorschläge angefügt.

Hinweis: Leider können wir für die hier aufgezeigten Lösungsvorschläge nicht garantieren und übernehmen keinerlei Haftung.


Ein Beispiel zur Problematik (Stand: 13.06.2014)

Bisher reichte die Angabe der Datenschutzbestimmungen im Impressum oder in einem entsprechend benannten Teil. Das Problem hierbei ist einfach erklärt: der Seitenbesucher kommt auf die Seite und sucht sofort die Datenschutzbestimmungen auf und entscheidet sich dann die Bestimmungen nicht zu akzeptieren und die Seite zu verlassen. Währenddessen sind aber schon sämtliche Plugins bereits geladen und aktiv bzw. schon Tracking-Cookies gesetzt (z.B. durch Google Analytics). Hierbei sollte bedacht werden, dass einige dieser Cookies bis über das Jahr 2040 gespeichert bleiben, jedenfalls theoretisch, und obwohl der Seitenbesucher weder noch in Facebook eingeloggt ist oder bei Google, legen sich trotzdem Cookies an, die bei einem späteren Zeitpunkt einer Anmeldung bei einem dieser Dienste wieder rekursiv aufgewickelt werden können. Denn, währenddessen hat das System den Seitenbesucher, der bisher nur unter der ID XYZ bekannt gewesen ist, verfolgen können und kennt bereits bestimmte Vorlieben für Waren oder Interessen dieser Person, aber auch Region bzw. Stadt in der diese lebt, Sprache, Konsumverhalten, Mobilität und wahrscheinlich vieles mehr. Beispielsweise besteht nun die Möglichkeit, dass durch eine Anmeldung bei einem anderen Onlineanbieter diese Cookies zusammengeführt werden. So bekommt Person XYZ einen Namen, Adresse, Telefon, vielleicht sogar noch mit Informationen über den Freundes- und Bekanntheitskreis. Nicht nur dass, bei einer Anmeldung räumt man dem Anbieter in der Regel sogar erweiterte Rechte an den Daten ein, die dem Netzwerk übermittelt werden. Sogesehen können das Daten sein, die zu dieser Zeit noch gar keine Berechtigung für diese Art der Verwendung hatten.

Tracking-Cookies / Cookies allgemein: (Stand: 13.06.2014)

Auch wenn durch den Einsatz von Tracking-Cookies keinerlei persönliche Daten übertragen werden (wie Name, Telefon, etc.) liegt dennoch eine systematische und gezielte Referenzierung sowie Verfolgung und spätere Identifizierung des Seitenbesuchers vor, ohne dass er vorher davon in angemessener Weise in Kenntnis gesetzt wurde sowie die Möglichkeit hatte dies zuzustimmen. Zudem können Tracking Cookies auch von fremden Anbietern ausgewertet oder sogar zusammengeführt werden. Ein Sicherheitsrisiko ist das Auslesen von Cookies durch Schadsoftware.

Insgesamt wird der "stille" Einsatz von Cookies in Frage gestellt, besonders wenn Cookies über einen längeren Zeitraum gespeichert bleiben sollen, da das Merken von Zuständen eine Speicherung von echten Aktionen des Seitenbesuchers, auch wenn nur in abstrakter Form, darstellt. Mit Ausnahme von: Sitzungs-Cookies mit Sessions, die für den Zugang in ein Loginbereich oder die Inhalte eines temporären Warenkorbs eingesetzt werden. Aber auch diese Daten dürfen nicht ohne Weiteres einfach in Cookies abgelegt und fortwährend dort bestehen bleiben. Deshalb werden die geschützten Cookie-Sitzungsdaten selbst auf dem Server gespeichert und mit einem eindeutigen Schlüssel (Session-Cookie) referenziert der automatisch verfällt beim verlassen der Seite, beim schließen des Browsers oder Fensters sowie bei Inaktivität. Zudem wird keine Beziehung zwischen Person und Internetseite hergestellt, die sich zu einem späteren Zeitpunkt verfolgen lässt. Auch eine Re-Identifizierung bei einem späteren Besuch derselben Seite, ist ohne Login-Funktion nicht möglich.

Empindliche Daten wie Name, Kontaktdaten, Passwörter, usw. sollten generell niemals in Cookies als Klartext abgelegt werden, wenn erforderlich dann nur in verschlüsselter Form. Andernfalls besteht z.B. die Möglichkeit, dass Dritte zu einem späteren Zeitpunkt Cookiedaten auslesen können, ohne dass der Seitenbesucher davon wusste, dass sein Passwort oder andere empfindliche Daten dort abgelegt worden sind. Daher gibt es bei Login-Vorgängen auch häufig die Zusatz-Funktion "Passwort merken" oder "eingeloggt bleiben". Hier hat man in der Vergangenheit schon reagiert, wobei erst nach Zustimmung (durch aktivieren der Option) ein zusätzlicher Cookie angelegt wird, der sehr viel länger als der von Haus aus geschützte Sitzungs-Cookie bestehen bleibt.

Mögliche Lösungen und Alternative:
  • Auf Cookies komplett verzichten, sofern es möglich ist
  • Beispielsweise kommen AJAX-basierte Webseiten auch ohne Cookies während einer Sitzung aus
  • Vor dem Setzen von Cookies Einverständniserklärung des Seitenbesuchers einholen (falls positiv: Entscheidung in Cookie speichern, Barrierefreiheit beachten)
  • Die Einverständniserklärung muss vollständig offen legen, in welcher Weise die Cookies verwendet werden (ggf. auch mit weiteren Datenschutzhinweisen), andernfalls ist die Erklärung nicht gültig
  • Alternative zu Cookies: Server-seitige "Sessions" benutzen und ggf. die Sitzungs-ID per URL übertragen oder Sitzungs-Cookie verwenden.


Google Analytics:

Kann im Grunde allein schon wegen der Cookie-Problematik (siehe oben) nicht eingesetzt werden (auch hier: systematische und gezielte Referenzierung sowie Verfolgung des Seitenbesuchers), ohne dass der Seitenbesucher vorher davon in angemessener Weise in Kenntnis gesetzt wurde sowie die Möglichkeit hatte dies zuzustimmen. Eine Übertragung der vollständigen IP des Seitenbesuchers kann eine Rechtsverletzung darstellen und lässt sich beim aktuellen Analytics-Plug-in von Google zwar manuell einschränken, aber eine 100%-ige Garantie ist es nicht.

Kritisiert wird häufig auch die "Grauzone" bei der Datenübermittlung an Google, wodurch der Seitenbetreiber selbst nicht in der Lage ist vollständig nachzuvollziehen, welche Daten tatsächlich vom Seitenbesucher abgefragt und übertragen werden. Darüber hinaus sind die Möglichkeiten solche Daten einzusehen oder zu löschen unzureichend. Ein Blick in den Quellcode des Plug-ins hat uns zudem gezeigt, dass sogar Mausbewegungen oder andere Interaktionen des Seitenbesuchers interpretiert werden können!

Mögliche Lösungen und Alternative:
  • Vor dem Einbinden des Plug-ins Einverständniserklärung des Seitenbesuchers einholen
  • Die Einverständniserklärung muss vollständig offen legen, was das Plug-in genau macht (ggf. auch mit weiteren Datenschutzhinweisen), andernfalls ist die Erklärung nicht gültig
  • Auf sämtliche externe Anbieter für automatisierte Webseitenanalyse verzichten und eine eigene, Datenschutz-freundliche Lösung implementieren
  • Alternativ: Google Analytics Server-seitig implementieren z.B. mithilfe der Bibliothek "ga-php" (funktioniert ohne Cookies), hier kann zum einen kontrolliert werden welche Daten in welcher Form übermittelt werden, zum anderen lassen sich Attribute einstellen und vor dem Absenden manipulieren (z.B. manuell gekürzte IP übertragen)


Soziale Netzwerke Plug-ins / Plug-ins allgemein

Generell ist die Verwendung von externen Plug-ins insoweit fragwürdig, da hier ähnlich wie bei Google Analytics nicht vollständig nachvollzogen werden kann, welche Daten in welcher Form übertragen werden und was mit diesen Daten nach der Übertragung weiterhin geschieht. Auch hier: die Möglichkeiten diese Daten einzusehen oder zu löschen sind nicht ausreichend für den deutschen Gesetzgeber. Die meisten dieser Plug-ins verwendet zusätzlich Cookies und verfügen oft auch über ein eigenes Tracking-System, wodurch die oben genannten Probleme auch noch hinzu kommen.

Beispielsweise wird durch das einfache Einbinden des Facebook-Plug-ins gemäß Vorgabe, was in der Regel nur ein kleiner Codeschnipsel ist, in Wirklichkeit Unmengen von Code nachgeladen und ausgeführt. Ein Blick in den Profiler der Javascript-Umgebung zeigt: Es wird mit Code förmlich überladen (nicht zu vergessen für einen einzigen Like-Button). Zudem wird der Seitenstart sowie der Aufbau der Seite extrem verzögert, selbst die Seitenperformance nachdem alles geladen ist leidet stark. Da fragt man sich natürlich schon, was da im Hintergrund so alles abläuft. Zu beobachten war auch eine aktive, fortwährende Verbindung zu einigen Skripten, ähnlich wie bei einem Chat mit offenem Kommunikationskanal, wodurch Daten ohne „GET“ oder „POST“ im Hintergrund stetig übermittelt werden können.

Mögliche Lösungen und Alternative:
  • Direkte Einbindung dieser Plug-ins (sofortigem Start) vermeiden
  • Plug-ins dynamisch nachladen und vor dem Einbinden des Plug-ins Einverständniserklärung des Seitenbesuchers einholen, auch für die Nutzung von Cookies o. a. falls erforderlich
  • Die Einverständniserklärung muss vollständig offen legen, in welcher Weise die Plug-ins funktionieren (ggf. auch mit weiteren Datenschutzhinweisen), andernfalls ist die Erklärung nicht gültig
  • Alternativ: 2-Klick-Variante einer Open-Source-Lösung (Einblick und Überprüfung des Quelltextes sollte auch hier gegeben sein) oder das Prinzip selbst nachbauen, indem die Plug-ins mit eigenen Grafiken ersetzt und angedeutet werden und erst bei Klick das echte Plug-in geladen und ausgeführt wird. Hier muss darauf geachtet werden, das wiederum ein kurzer Hinweis für den Seitenbesucher vor dem Nachladen des echten Plug-ins erscheinen muss (z.B. per Tooltip). Zusätzlich sollten sogenannte statische Links zu den Funktionen der sozialen Netzwerke genutzt werden via <a href=““ target="_blank"> oder window.open(), die sich somit in einem neuen Fenster/Tab öffnen und nicht mehr Teil des eigenen Internetangebotes sind. Eine Verlinkung auf externe Seiten ist generell erlaubt.


Fazit

Letztendlich kann man sagen, es lassen sich mit entsprechender Hinweisbeigabe und nachträglicher Integration alle Funktionen weiterhin nutzen. Wer auf spezielle Hinweise oder Einverständniserklärungen verzichten möchte, kann die oberhalb aufgeführten Alternativen als Anregung nutzen.

Falls Bedarf besteht, stellen wir hier gern noch ein paar Codebeispiele zur freien Verfügung, die für jedes hier aufgeführte Problem eine Möglichkeit zu einer alternativen Lösung aufzeigen.



Mittwoch, 4. Juni 2014

Notlösung für Fehler in Google Chrome bei "background-attachment:fixed" (Bugfix)

Es ist schon kaum zu glauben, dass diesmal nicht der Internet Explorer der Sündenbock ist. Unzwar erzeugt der Google-Browser Chrome in einigen Situationen einen Anzeigefehler bei der Verwendung von Seiten-fixierten Hintergrundbildern (z.B. wenn die Fixierung nicht am Seitenstart stattfindet und oberhalb verdeckt werden soll). Der Fehler äußert sich so, dass die Hintergrundbilder nicht fixiert sind und sich stattdessen um ein Vielfaches beim scrollen überlagern. Das kann bis hin zu bizarren Bildmosaiken führen, die dem Seitenbesucher das Gefühl vermittelt, die Grafikkarte sei kaputt. Leider lässt sich dieses Problem nicht ohne die Verwendung von JavaScript umgehen. Hier bliebe nur noch die Änderung des Designs (oder zumindest das Ändern der CSS-Direktive von "fixed" zu "scroll").

Nach etwas längerer Recherche und unzählig vielen Lösungsansätzen, die wir probiert aber leider nicht geholfen haben, konnten wir zumindest die Ursache mithilfe diesen Blog-Eintrags feststellen:

» Andrew Cantino: "Fixing the Chrome Background Refresh Bug"


Was verursacht diesen Fehler in Google Chrome?

Nahezu alle modernen Browser nutzen eine Technologie die häufig auch "Z-Buffering" genannt wird (Verdeckungsoptimierte Berechnung), um mehr Performance zu erreichen. Somit werden nur sichtbare Bereiche, die sich auf der Seite ändern, aktualisiert und vom Browser neugezeichnet. Leider hat der Chrome Browser einen Bug bei der Verarbeitung von fixierten Hintergrundbildern und geht irrtümlicherweise davon aus, dass das Element nicht zu sehen wäre und zeichnet dieses bei Änderungen nicht nach. In diesem Fall muss das Nachzeichnen explizit erzwungen werden, unzwar bei jeder Scroll-Bewegung auf der Seite.

Der Ansatz von Andrew Cantino aus dem oberen Link löst zwar das Problem, erzeugt dafür aber auch ein kurzes Flackern der Seite beim Scrollen. Verursacht wird dies durch das kurze Ein- und Ausblenden der fixierten Hintegrundebene. Damit ein Element vom Browser vollständig nachgezeichnet wird, muss ein Attribut geändert werden, welches sich auf die gesamte Fläche des Elementes auswirkt und zugleich tatsächlich auch sichtbar ist. Wir haben dies getestet. Auch dieses Verhalten gehört zur Verdeckungsoptimierten Berechnung und soll den Browser bei seiner Darstellung beschleunigen.

Wir haben die Idee verbessert und eine Lösung gefunden, die einerseits für das menschliche Auge unsichtbar ist, aber trotzdem dem Browser vorgaukelt, es sei eine Änderung aufgetreten.


Google Chrome Fix for "background-attachment:fixed" (jQuery)

Angenommen es gibt ein Element mit fixiertem Hintergrundbild:
Problemlösung: Diese relativ simple jQuery-Erweiterung rüstet die Objektfunktion "repaint()" an einem beliebigen jQuery-Selektor nach: Anwendungsbeispiel: So kann die Funktion dann initialisiert und genutzt werden: Hier wird zunächst geprüft ob die Seite mit dem Browser Chrome aufgerufen wurde. In diesem Fall wird das Scroll-Ereignis abgefangen/erweitert und löst das Neuzeichnen der übergebenen Elemente durch die Funktion "repaint()" aus. Mit dieser Methode können beliebig viele fixierten Hintergrundbilder auf derselben Seite aktualisiert werden. Lediglich der jQuery-Selektor muss beim Funktionsaufruf von "repaint()" geändert werden.

Zugegeben, diese Methode ist nicht gerade elegant, aber bei ungewöhnlichen Fehlern bleibt einen manchmal nichts anderes übrig als ungewöhnliche Mittel einzusetzen.