Tech-Post: Wie funktioniert das technische Javascript-Innenleben des Optimizely-Snippets?




Nach unserer Session bei der WebTech Conference in München letzte Woche habe ich mit drei Teilnehmern darüber gesprochen, wie Optimizely technisch funktioniert. Ich werde das deshalb in diesem Blogpost zusammenfassen.

Eine Warnung vorweg: um Optimizely als Tool nutzen zu können, muss man das alles nicht verstanden oder gelesen haben.

Das meiste, was Optimizely tut, findet clientseitig im Browser des Besuchers statt und nennt sich DOM-Manipulation. Wir erstellen und aktualisieren eine Javascript-Datei auf unseren Servern, die all diese Logik enthält, und die auf Ihrer Seite als eine Art Snippet (oder Tag) synchron eingebunden wird.

Wie entscheidet sich also, welche Besucher welche Experimente und Varianten zu sehen bekommen?

Kommt ein Besucher auf Ihre Seite, weisen wir ihm eine eindeutige ID zu über die wir ihn bei Folgebesuchen wiedererkennen können. Wir schauen außerdem nach, in welche Segmente der Besucher gehört (also beispielsweise mobile oder nicht-mobile Browsernutzer). Diese Information hinterlegen wir in Cookies im Browser des Besuchers (optimizelyEndUserId und optimizelySegments).

Unser Javascript-Code kontrolliert dann, ob der Besucher die Targeting-Kriterien für ein oder mehrere Experimente erfüllt. Falls dem nicht so ist, stoppt unserer Logik hier und die Seite wird im Original dargestellt.

Wenn der Besucher für eines oder mehrere Experimente die Targeting-Kriterien erfüllt, entscheiden wir durch einen Traffic-Zuteilungsalgorithmus, ob der Besucher teilnehmen soll und welche Variation er zu Gesicht bekommt. Diese Entscheidung speichern wir dann wieder in einem Cookie (optimizelyBuckets) für folgende Besuche und Seitenaufrufe.

Optimizely-Nutzer haben die Möglichkeit globales CSS und Javascript für ein Experiment zu hinterlegen. Dieses wird and dieser Stelle eingefügt und ausgeführt. Danach wird der variantenspezifische Javascript-Code (den entweder der visuelle Optimizely-Editor oder einer Ihrer Entwickler erstellt hat) ausgeführt. Im nächsten Abschnitt dieses Posts gehe ich hierauf näher ein.

Die Hauptmagie Ihres Experiments hat stattgefunden. Es werden nun noch Klickziele an die Seitenelemente gebunden, die Sie tracken möchten. (So erstellen Sie ein Klickziel.) Und es lädt natürlich der Rest der Seite.

Im Anschluss daran schicken wir noch einen Request zu unserem Tracking-Server, der Optimizely mitteilt, dass der Besucher die Seite gesehen hat (um beispielsweise Pageview-Ziele tracken zu können).

Noch einmal Schritt für Schritt im Überblick:

Ablaufreihenfolge der Operationen des Optimizely-Snippets

Wie stellt Optimizely sicher, dass das Original der Seite nicht kurz auf dem Bildschirm erscheint (aufflackert) bevor die Variantenänderungen durchgeführt wurden?

Wer schon einmal visuelle Änderungen an einer Seite mit Javascript / jQuery durchgeführt hat, weiß, dass es zu Timing-Problemen kommen kann: Die Seite wird bereits dargestellt bevor die Änderungen durchgeführt und neu gerendert werden.

Das hängt damit zusammen, dass Entwickler traditionell solche Änderungen erst vornehmen, wenn das DOM-Ready-Event gefeuert wurde (und deshalb sichergestellt ist, dass alle Seitenelemente im Browserspeicher vorhanden sind). Hierdurch kann man sichergehen, dass alle Elemente bearbeitet werden können, leider sind sie dann aber meistens auch schon auf dem Bildschirm sichtbar.

Wir bei Optimizely verwenden einen, wie wir finden, klügeren Mechanismus, um das zu verhindern. Wir müssen einerseits sicherstellen, dass Code so schnell wie möglich ausgeführt wird, andererseits müssen wir aber auch warten bis die zu ändernden Elemente im Browserspeicher verfügbar sind. Was nicht da ist, können wir ja auch noch nicht ändern.

Der Javascript-Code (jQuery), der von unserem visuellen Editor im Hintergrund generiert wird, folgt einem festen Schema:

$("img#hplogo").attr({"src":"//cdn.optimizely.com/img/a/05ac207c778548959fe1ff374d111296.gif"});

Der erste Teil in diesem Beispiel legt fest, welches Element verändert werden soll, der zweite, was gemacht werden soll. In diesem Beispiel soll das Bild (‘img’) mit der ID ‘hplogo’ verändert werden. Der zweite Teil sagt aus, dass die Bildquelle (‘src’) auf ein bei Optimizely hochgeladenes Bild abgeändert werden.

Wenn Optimizely den Javascript-Variationscode ausführt (und zu dieser Zeit das DOM-Ready-Event noch nicht gefeuert ist, also nicht sowieso schon alle Seitenelemente im Browserspeicher verfügbar sind), schauen wir also Zeile für Zeile, ob das, was da steht, mit unserer Schema-Vorlage übereinstimmt. Wir verwenden dafür den folgenden regulären Ausdruck:

^\$j?\((['"].+?['"]|document)\)\..+;(?:\s|(?:\/\/.*|\/\*(?:[^*]|\*(?!\/))*\*\/))*$

Wenn es das tut, schauen wir, ob das Element schon im DOM-Baum gefunden und bearbeitet werden kann. Fall nicht, warten wir 50ms und wiederholen diesen Schritt solange bis das Element verfügbar ist. Falls das Element mittlerweile bereit ist, führen wir die Änderung durch – in den allermeisten Fällen bevor Ihr Besucher das Element jemals zu Gesicht bekommen hat.

Wenn die Zeile Javascript nicht unserem Schema entspricht, gehen wir davon aus, dass es sich um manuell von einem Entwickler erstelltes Javascript handeln muss (also nicht von unserem visuellen Editor) und warten mit dem Ausführen dieser Zeile bis die DOM komplett bereit ist. Wir gehen hier davon aus, dass der Entwickler, der daran gearbeitet hat, seine eigene Strategie entwickelt hat um mit diesem Problem umzugehen. Falls Sie gerade in dieser Situation stecken und nicht weiter wissen, kontaktieren Sie uns einfach über unser Support-Formular und wir helfen Ihnen gerne auf die Sprünge! Haben Sie eine Ultimativlösung für diese Herausforderung gefunden? Hinterlassen Sie uns einen Kommentar unter diesem Post. Wir sind gespannt!

Hier noch einmal die komplette Logik, aufbereitet in einer (zugegebenerweise nicht ganz simplen Skizze):

Ausführungslogik für die Optimizely-DOM-Manipulation