Browsed by
Schlagwort: javascript

Javascript schöner und schneller machen

Javascript schöner und schneller machen

Javascript ist, angesichts seiner etwas holprigen Entstehungsgeschichte eine eigentlich recht elegante Scriptsprache. Es krankt jedoch daran, dass in Javascript im Grunde alles geht und alles gemacht wird und jedesmal anders. Will man mit Kollegen zusammen an einem Javascriptprojekt arbeiten, ist der eigene Dialekt ebenso hinderlich, wie mangelnde Sauberkeit beim Codeschreiben. Beachtet man aber neben einem guten Stil in Javascript einige elementare Regeln, kann man seine Scripte dadurch auch noch merklich schneller und kompakter machen.

Coding Guidelines

In Sachen Coding Guidelines gilt auf jeden Fall: jede Regel ist besser als keine Regel. In Javascript kann man viele böse Dinge schreiben, die kein Mensch versteht, die aber trotzdem hervorragend funktionieren. Die Sprache lässt einfach vieles zu, was trotzdem schlechter Stil ist. Vor kurzem haben sich die Entwickler von jQuery einen Styleguide verpasst, die JQuery Core Style Guidelines, das ist schon eine wunderbare Grundlage. Einfach copy & pasten.

Wichtig ist dabei auch, die Verwendung von JS Lint (JSLint will hurt your feelings.). Mit diesem Tool kann man die übelsten Stylefehler vermeiden und die Einhaltung des Styleguides automatisiert überprüfen. Die Einführung dazu ist mehr als lesenswert. Besonders praktisch für Nutzer von Textmate (Lieblingseditor) ist das JS Lint Bundle.

Codeverbesserung: erster Durchgang

Sich aufzuraffen, seinen Code zu überarbeiten, ist nicht leicht. Aber: der Wille zur Verbesserung und das Wissen, dass der erste Aufschlag meist nicht optimal ist, trennt den Programmieren vom Scriptingguy, oder so. Hier ein paar schnelle und einfache Schritte, die Javascript schon deutlich verbessern. Federice Galassi hat darüber eine wunderbare Präsentation gemacht. Die Maßnahmen führen aber nicht nur in Richtung unobtrusiveness, sondern sind auch geeignet, Javascript schneller und wartbarer zu machen. Kurz zusammengefasst:

  1. Entferne alles Inline-Javascript aus dem HTML-Code.

    Also <script> Code…</script> raus aus den Seiten und in eigene Dateien (besser eine eintige) packen. Diese dann mit <script src="datei.js"></script> aufrufen. Und das am besten am Ende der Seite, direkt vor </body>.

  2. Alle Inlineevents aus dem HTML entfernen

    Weg mit <a class="klick" href="#" onclick="foo();">Klicken Sie hier</a>. Das kann besser machen. Mit jQuery beispielsweise: $("a.klick" ).bind("click", function() { foo(); });, jedenfalls aber in der externen Javascriptdatei.

  3. Javascript-Pseudolinks entfernen

    Mit Todesstrafe wird der uralte Javascript-Pseudolink bestraft! Sowas geht gar nicht: <a href="javascript:foo()">Klicken Sie hier</a>

  4. CSS-Code aus dem Javascript entfernen.

    Innerhalb des Javascriptes sollte kein CSS verwendet werden (Trennung von Präsentation und Programmierlogik). D.h. sowohl Zuweisungen wie $("a" ).css("background","#ff0000" ); oder auch document.getElementById("id").style.color("#ff0000"); und ähnliches schreiben teilweise lange unüberschaubare style-Attribute in den HTML-Code und produzieren DOM-Zugriffe. Stattdessen schreibt man die CSS-Anweisungen in eine CSS-Datei

    [css]
    // bspw. base.css
    a.rot {
    background: #ff0000;
    }
    [/css]

    und nutzt im Javascript

    [js]
    $("a").addClass("rot"); // Farbe an
    $("a").removeClass("rot"); // Farbe aus, oder gleich:
    $("a").toggleClass("rot"); // je nach dem
    [/js]

    CSS bewegt sich wesentlich schneller und gewandter durch das DOM als Javascript.

  5. Businesslogik aus dem Javascript entfernen (Client-Server-Anwendungen).

    Bei Client-Server-Anwendungen kann es einen entscheidenen Geschwindigkeitsvorteil bedeuten, komplizierte Berechnungen nicht auf dem Client (also mit Javascript) sondern auf dem Server auszuführen. Wenn man sich also schon Daten vom Server holt, dann sollte man vermeiden mit diesen Daten Berechnungen auf dem Client auszuführen. Ein Beispiel:

    [js]
    // Schlecht!
    $.get("action.php", function ( data ) {
    if ( data ) {
    if ( data.kontostand > data.dispokredit ) {
    alert("Konto überzogen" );
    }
    }
    });

    // Besser!
    $.get("action.php?dispoberechnung", {konto:"123456"}, function ( data ) {
    if ( data.dispo === false ) {
    alert("Konto überzogen" );
    }
    }
    [/js]

  6. DOM-Operationen auf ein Minimum beschränken!

    Nicolas Zakas formuliert es in High Performance JavaScript (Build Faster Web Application Interfaces) so:

    An excellent analogy is to think of DOM as a piece of land and JavaScript (meaning ECMAScript) as another piece of land, both connected with a toll bridge (see John Hrvatin, Microsoft, MIX09, http://videos.visitmix.com/MIX09/T53F ). Every time your ECMAScript needs access to the DOM, you have to cross this bridge and pay the performance toll fee. The more you work with the DOM, the more you pay. So the general recommendation is to cross that bridge as few times as possible and strive to stay in ECMAScript land.

    Daraus ergibt sich eine klare Anweisung: greife sowenig wie es eben geht auf das DOM zu.

    Ein Domzugriff ist dann gegeben, wenn ein DOM-Element erschafft, ins DOM einhängt, ein Element im DOM verschiebt, Attribute hinzufügt und so weiter und so fort. Am allerschlimmsten sind die sogenannte HTML-Coolections und das iterieren hierauf.

    [js]
    // ein ganz böses Beispiel!
    function innerHTMLLoop () {
    for ( var i = 0; i < 15000; i++ ) {
    document.getElementById("meinLink" ).innerHTML +="a";
    }
    }
    [/js]

    Hier erleben wir schlappen 15000 DOM-Aufrufe der übelsten Art. Stattdessen vermeidet man solange wie möglich den Zugriff aufs DOM:
    [js]
    // dann besser so
    function innerHTMLLoop2 () {
    var content ="";
    for ( var i = 0; i < 15000; i++ ) {
    content +="a";
    }
    document.getElementById("meinLink" ).innerHTML += content;
    }
    [/js]

    Goldene Regel: pro Funktion sollte es nur einen Zugriff auf den DOM geben. So kann es beispielsweise Sinn machen, sehr lange auf Strings mit HTML zu arbeiten und erst am Ende alles zusammen per $( var ).appendTo( 'body' ); ins DOM zu hängen. Ausser in Chrome und Safari ist es sogar noch schneller innerHTML zu benutzen, in jQuery $("#meinKram" ).html( var );. Hier scheiden sich allerdings die Geister, weil innerHTML nicht standardkonform ist, wohl aber von jedem Browser unterstützt wird.

  7. Große HTML-Chunks ggf. durch Templates ersetzen.

    Wegen der schon oft angesprochenen Trennung von Content und Präsentationslogik ist zu überlegen, ob man für große HTML-Stücke die man in den Code einspeisen muss, vielleicht besser HTML-Templates verwendet, den Code also in externe Dateien auslagert und nachlädt (auf welche Weise auch immer). Als Vorstufe dazu und Kompromiss kann man auch bis mittelgroße Codeschnipsel im verborgenen Teilen des HTML-Dokuments unterbringen und sich dann per .clone() oder wieder .html() einlesen und wiederverwenden.

    Die Verwendung eines Templatesystems setzt aber bspw. wieder ein eingenes Plugin voraus, Schnipsel im HTML verursachen beim Laden wieder DOM-Zugriffe. Hier muss man genau abwiegen, was der Performance hier zuträglich ist, sicherlich auch in Abhängigkeit vom der Größe des HTML-Codes der benötigt wird.

  8. Keine/wenig globalen Variablen nutzen!

    Variablen die ausserhalb von Funktionen definiert werden, sind, auch wenn sie mit var geschrieben werden, globale Variablen, die im window-Namensraum gespeichert werden. Es besteht die Gefahr, dass diese an anderer Stelle ungewollt überschrieben werden, außerdem ist der Zugriff auf window langsam. Stattdessen speichert man Variablen aus dem Window-Namensraum in lokalen Variablen zwischen, auf die der Zugriff wesentlich schneller erfolgt.

Fortsetzung folgt

Dieser 8-Punkte-Plan ist aber nur ein Einstieg. Wenn man ein Programm so optimiert hat, kann man praktisch direkt wieder von vorne anfangen und weitere Verbesserungen einbringen. Das wird dann das Thema eines weiteren Artikels hier.

Die iPad Webseite

Die iPad Webseite

Screenshot ZEIT ONLINE, Wissen Centerpage, iPad Version, Design: Information Architects

Liest man die gängigen Webdesign-Sites findet man eine Fülle von Tipps, wie man seine Website anpassen kann, damit sie auch auf dem iPad funktioniert. Der Tenor: mit css media queries ein paar zusätzliche Stylesheets für das iPad liefern, im Scriptteil ein wenig die Touch- und Gestureevents einsetzen, Flashvideos raus, Buttons größer: fertig! Das war nicht ganz das, was uns vorschwebte…

Das mit den media queries ist so eine Sache

Kurz gesagt: CSS media queries sind im Moment eine schicke und elegante Lösung, wenn man seine bestehende Website mit ein paar Handgriffen an die Gegebenheiten verschiedener, zumeist kleinerer, Displays anpassen will. Ebenso taugen sie sicherlich dazu, eine Web-App zu bauen, die nur auf Tablets funktioniert und im Desktopbrowser leer oder ungestyled bleibt (aber wer will das schon?). Für eine große Contentwebsite, die zweigleisig unter der gleichen Adresse unterschiedliche Styles an Desktopbrowser und Tablets ausliefert, sind sie jedoch (zumindest im Moment) nicht zu gebrauchen.

Das liegt zunächst einmal daran, dass mit Mediaqueries eingeschränkte Stylesheets zunächst mal allesamt heruntergeladen werden und dann entschieden wird, was angezeigt wird. Für den mobilen Einsatz und auch für den Tableteinsatz kommen sie damit kaum in Frage. Beim ersteren schon allein wegen der Downloadmengen, beim letzteren kommen wie die Erfahrung zeigt noch weitere Datenmengen an Javascript und z.B. größeren Bildern hinzu. Ein Fass ohne Boden.

Die von mir zunächst favorisierte Lösung führte aber dazu, dass nicht nur IEs kleiner Version 9 via conditional comments eigene Stylesheets zugeteilt bekommen mussten, auch Firefox 3.0 und kleiner können mit den mediumabhängigen Styles so gar nichts anfangen.

Das offizielle Video zum Launch

Ohne Javascript geht’s (derzeit) nicht

Und auf tut sich die böse Tür des user agent switching. Zwar gibt es eine Javascript-Lib, die css media queries gewissermassen emuliert, das ist aber ein weiterer gut 20kB großer Download ist, ein Monster mithin, das zudem nur mit Queries innerhalb von CSS-Dateien, aber nicht innerhalb von <link /> zulässt.

Stehen zusätzlich Anforderungen im Raum, dass auch ein Schalter zur Rückkehr zur klassischen Website eingebaut werden soll, oder wenn man feststellt, dass eben Tablet nicht geleich Tablet ist, man also für verschiedene Tablets noch kleinere Anpassungen vornehmen muss, dann ist man schnell dabei auf den user agent zu schauen. <interlude>Das vereinfacht übrigens auch gewaltig die Entwicklung der Seite, da man sie während des Bauens parallel zum iPad/iPad-Simulator auch im Firefox previewen kann. Das geht natürlich nur mit User Agent Switcher. Dann aber kann man den geliebten Firebug nutzen um wenigestens die Elemente auf der Seite und ihre Styles zu indentifizieren und auch das Scriptdebugging ein wenig zu unterstützen. Dinge die es auf dem iPad nicht oder nur sehr rudimentär gibt.</interlude>

Diese Lösung ist allerdings noch nicht das Endstadium, allein weil wir nach und nach die Site für weitere Tablets fit machen wollen. Im Laufe dieser Zeit werden wir auch das UA-switching wieder entfernen und durch bessere Methoden ersetzen.

Screenshot ZEIT ONLINE, Navigation, iPad Version, Design: Information Architects

Der Spass an der Entwicklung

Eins muss man gleich sagen: Entwicklung für Tablet (speziell das iPad) macht einen Heidenspaß. Zum einen ist die Touchbedienung faszinierend. Ich bin so einer, der ein mouse-over-Menü entwickelt und sich dann stundenlang daran erfreuen kann, wie beim Hovern über den Menüpunkt das Menü animiert ausfährt. Auf dem Tablet kann man solche Lösung praktisch zum Anfassen programmieren (natürlich ohne :hover). Ich habe das Menü bestimmt mehrere tausend Mal ausprobiert. Oder die Bildergalerien (obwohl ich da noch nicht zufrieden bin). Die Möglichkeiten des Webkit sind wirklich hervorragend und das geniesst man natürlich. Obwohl es auch ein wenig zu verführerisch ist, wenn man in die Hölle der Desktopbrowser zurückkehrt und feststellt, dass es da draussen immer noch Internet Explorer gibt… 😉

Kleinere Schlaglöcher

Ein paar Dinge waren allerdings echte Kopfnüsse. Da ist zum Beispiel der Viewport-Tag. Schon bei diesem Blog hier habe ich Probleme damit gehabt. über diesen einen Tag den Viewport und vor allem die Vergrößerung so zu setzen, dass es für iPad und iPhone gleichermaßen funktioniert. Das Design der iPad-Seite erforderte ganz klar ein:

[html]<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">[/html]

Das passt allerdings nicht zu unserer Art, das iPhone zu bedienen. iPhone-Nutzer werden beim Besuch gefragt, ob sie die mobile Website besuchen möchten, oder die klassische Seite. Mit dem obigen Meta-Tag kann man diese dann aber auf dem iPhone nicht mehr skalieren. Für das iPhone empfiehlt sich eher:

[html]<meta name="viewport" content="width=device-width">[/html]

Will man allerdings (für das iPad) zwei Ansichten für Portrait- und Landscapemodus präsentieren (vs. vergrößerte Portraitansicht im Landscapemodus), dann ist man auf das minimum-scale=1.0, maximum-scale=1.0 festgelegt.

Überraschenderweise kann man aber auch diesen Metatag per Javascript setzen! Es hat allerdings ein wenig gedauert, bis ich das einfach mal ausprobiert habe (hüstel). Außerdem musste dafür ganz schön an unserer Seitenstruktur geschraubt werden.

Wie geht’s weiter?

Zunächst mal kommen jetzt schnell weitere Tablets dazu, mit denen man die Seite betrachten kann. Es war leider schnell klar, dass man mit einem Schlag nicht alle Tablets bedienen kann. Mindestens an den Einstellungen des Viewports müssen Anpassungen gemacht werden, wahrscheinlich auch etwas CSS und Script. Wobei, wir wollen jetzt auch nicht jedes Tablet das neu auf den Markt kommt kaufen (der Gadgetjäger in mir fragt natürlich: »warum eigentlich nicht«). Man wird sehen, was sich am Tabletmarkt noch tut und was sich durchsetzt. Wir räumen zunächst mal dem Galaxy Tab von Samsung gute Chancen ein, und wenn RIM mit einem Tablet kommt, wird’s ja vielleicht auch nochmal interessant.

Abschließend sei gesagt, dass die Sache natürlich ein gutes Stück weit vom Design der Information Architects lebt, Oliver Reichenstein hat dazu einen schönen Artikel geschrieben, der auch die – ich nenne es mal so – medienpolitischen Hintergründe gut erfasst und viel von dem Geist beschreibt, der hinter dieser Webapp steckt.

Noch ein paar Artikel und Stimmen zum Thema: iPadMag, Editors Weblog, iPad Planet NL

10k Apart (by Microsoft)

10k Apart (by Microsoft)

Hurra, ein Wettbewerb.

Es hat sich längst rumgesprochen, unter dem Buzzword HTML5 hat die Entwicklung kleiner Applikationen im Web mit standardkonformen HTML, CSS3 und Javascript Einzug in die Welt der Webseiten gehalten. Eines Tages wird man wahrscheinlich doch noch davon sprechen können, HTML5-Seiten programmiert zu haben (oh-oh!).

Dabei sind die Apps die man jetzt schon kennt oft schwergewichtige Ungetüme aus HTML und vor allem Javascript. Das muss natürlich nicht so sein. Um all dem Rechnung zu tragen (und ein wenig Werbung zu betreiben) haben MIX (≅ Microsoft) und An Event Apart einen Wettbewerb ausgerufen: gesucht werden kleine HTML5-Apps, kleiner als 10K, wobei die Verwendung von jQuery, Prototype und Typekit als Webservices ausgenommen sind. Laufen sollen die Apps in der IE9 Preview, Firefox und einem Webkit Browser. Na, dann mal los…

Webkongress Erlangen 2010

Webkongress Erlangen 2010

Eine mittlere Premiere gibt es für den 7. und 8. Oktober in diesem Jahr zu verkünden. Der Webkongress Erlangen findet zu diesem Termin zwar schon zum dritten Mal statt, ich werde dort aber zum erste Male zu hören sein. Unter dem Titel »Relaunching ZEIT ONLINE« werde ich ein wenig über den Relaunch von zeit.de im September 2009, den Weg dorthin und den Erlebnissen seitdem berichten. Dabei geht es natürlich in der Hauptsache um den Fachbereich Frontendentwicklung und -technologie, sowie meine immerwehrenden Freunde: Usabilty und Accessibilty.

Nun kommen natürlich wegen mir alleine zu wenig Teilnehmer zu einem Kongress, deswegen sind weitere hochkarätige Webexperten geladen worden, bspw. Jens Grochtdreis, Vladimir Simovic und Alvar Freude. Übergeordnetes Thema des Kongresses sind Lösungen für barrierefreie Webseiten, soll heissen es geht nicht mehr nur um die Technik und den Prozess, sondern vielmehr um Webangebote, die diese Techniken auch ein- und umsetzen.

Mehr gibt es auf der Homepage des WKE 2010 nachzulesen. Man sieht sich.

Javascript unpacker and beautifier

Javascript unpacker and beautifier

This little beautifier will reformat and reindent bookmarklets, ugly javascript, unpack scripts packed by the popular Dean Edward’s packer, as well as deobfuscate scripts processed by javascriptobfuscator.com.

JS-Library: Namespace und erste Funktionen

JS-Library: Namespace und erste Funktionen

Eigentlich habe ich ja schon seit Ewigkeiten vor, mir eine eigene, kleine Javascript-Bibliothek zusammenzustellen, in der ich die immer wiederkehrenden Funktionen, die man in Javascript so benutzt, zusammengefasst sind. Allerdings: es mangelte bis dato an der nötigen Ernsthaftigkeit, so etwas tatsächlich umzusetzen. Also dann jetzt: ich werde hier in Zukunft Funktionen etc. zusammentragen und zu meiner kleinen Library zusammenfügen. Dabei kann der geneigte Leser natürlich nicht nur zu schauen, sondern es ist durchaus erwünscht, mir dabei reichlich auf die Finger zu hauen und Verbesserungen vorzuschlagen.

Zunächst mal hab ich mir Gedanken um den Namespace meines Projektes gemacht. Heutzutage schreibt man natürlich keine Library, deren Funktionen fleissig in das window-Objekt geballert werden. Außerdem kann man dem Kind dann auch noch einen schlicken Namen geben.

Es gibt mehrere Methoden, einen Namespace zu kreieren, mir gefällt das Modell von Dustin Diaz am besten, weil man dort die Möglichkeit hat, Methoden und Variablen sowohl public, oder auch private zu machen. Nehmen wir an meine kleine JS-Library solle „CCL“ heissen (als Abkürzung für Code Candies Library), dann funktioniert der Aufbau des Namespace so:

[js]var CCL = function() {
var private_var;
function private_method() {
// do stuff here
}
return {
method_1 : function() {
// do stuff here
},
method_2 : function() {
// do stuff here
}
};
}();[/js]

OK, also haben wir jetzt einen Namespace, beginnen wir also, erste Funktionen hinzuzufügen. Ich fummle gerade viel mit Cookies herum, also nutze ich regelmäßig drei Funktionen: Cookie anlegen/schreiben, Cookie auslesen und Cookie löschen. Diese sind deutlich PPKs Cookie-Methoden angelehnt.

[js]var CCL = function() {
return {
cookieCreate: function (name,value,days, domain) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
domain = domain ? " domain=" + domain + ";" : "";
document.cookie = name+"="+value+expires+"; path=/;" + domain;
},
cookieRead: function (name) {
var nameEQ = name + "=";
var ca = document.cookie.split(‚;‘);
for(var i=0;i &lt; ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==‘ ‚) c = c.substring(1,c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
}
return null;
},
cookieErase: function (name) {
ZEIT.cookieCreate(name,"",-1);
}
}
}();[/js]

Eine Sache ist aber noch blöd: man möchte ja nicht wirlich solche Funktionsnamen: „cookieCreate“, jetzt ist das ja noch übersichtlich, aber wenn meine Library anwächst… da findet man sich schnell nicht mehr zurecht. Schöner wäre ein Namespace im Namespace. Und dann sollte man Getter und Setter ja auch irgendwie als solche kennzeichnen. Das würde dann so aussehen:

[js]var CCL = function() {
return {
Cookie: {
get: function (name) {
var nameEQ = name + "=";
var ca = document.cookie.split(‚;‘);
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==‘ ‚) c = c.substring(1,c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
}
return null;
},
set: function (name, value, days, domain) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
domain = domain ? " domain=" + domain + ";" : "";
document.cookie = name+"="+value+expires+"; path=/;" + domain;
},
kill: function (name) {
this.set(name,"",-1);
} // last item: no comma!
}
};
}();[/js]

Hmmm… das bringt ja richtig Spass. Nun kann man schön „draussen“ die Funktionen nutzen. Ruft man ganz leicht auf:

[js light=“true“]CCL.Cookie.set(‚testcookie‘, ‚test‘, 5); // ommitting domain results in the page domain[/js]

Kann man auf der Demoseite ausprobieren.

ie-css3.js

ie-css3.js

ie-css3.js allows Internet Explorer to identify CSS3 pseudo selectors and render any style rules defined with them. Ich will das nicht!!1!

Chroma Hash

Chroma Hash

In bin mir ja bewusst, dass es strunzlangweilig ist, wenn ich wöchentlich hier einen Link auf ein jQuery-Plugin setze und dabei regelmäßig betonen muss, wie knarzgeil jQuery ist, was für wundervolle Programmierideen damit schon verwirklicht wurden und: dass es immer noch besser wird.

Trotzdem. Chroma Hash (via Ajaxian) ist wieder so eine Programmier- slash Designidee, da muss man einfach frohlocken. Los geht’s. Folgende Problemstellung: beim Registrieren für eine Website muss der User zweimal sein gewünschtes Passwort eingeben, wie üblich verdeckt durch Sternchen/Bullets. Vertippt man sich, muss man nach dem Abschicken des Formulars nochmal beide Passwörter eingeben. Und so fort. Chroma Hash macht aus den Eingaben einen MD5-Hash (der sich nicht zurückrechnen lässt) und daraus widerum kleine Farbbalken. Womit man sofort visuell erfassen kann (im Grunde schon beim Tippen), ob man in beide Felder das gleiche eingetragen hat.

Ja, das ist ein relatives kleines Usability-Gimmick, aber ein wirklich nettes. Einfach mal ausprobieren.

JSON-P Memory Leak

JSON-P Memory Leak

Mit der JSON-P-Methode sehr viele Script-Tags zu einem Dokument hinzuzufügen, kann in ein mittelschweres Speicherproblem führen…