Schneller, schöner, besser: LConf 1.3


Wer sich unsere Software gerne tippfrisch aus den git Repositories zieht hat es vielleicht Bemerkt: In den letzten Monaten hat sich bei LConf, unserem LDAP-basierten Icinga/Nagios® Konfigurationstool einiges getan – sowohl im Backend als auch im Frontend. Heute freue ich mich, nach langer Arbeit die RC Version 1.3.0. bekanntgeben zu dürfen.
Alles unter Kontrolle – auch bei großen Setups: 
LConf erlaubt es dem Admin, sein Icinga (natürlich auch Nagios®) Setup grafisch auf einem LDAP Server zu verwalten und sich aus diesem Baum die Monitoringkonfiguration zu exportieren. Durch die Baumstruktur, Aliase und Vererbung lassen sich dabei auch sehr große Monitoring setups bequem und übersichtlich verwalten – und das ohne an ein bestimmtes Frontend zur Datenverwaltung gebunden zu sein.
LConf besteht dabei aus zwei unterschiedlichen Projekten:

  • Einmal dem eigentlichen LConf CLI-Tool, das Icinga Konfigurationen aus dem LDAP Baum erstellen und bestehende Konfigurationen in den LDAP Baum Importieren kann. Auch verteilte Setups können mit LConf erstellt und verwaltet werden. Die Verteilung der einzelnen Konfigurationen auf die Satelliten übernimmt dabei der Exporter selbst.
  • Und zusätzlich unserem (optionalen) Icinga-Web Modul, für alle die es noch bequemer wollen. LConf lässt sich mit zwar mit jedem beliebigen LDAP Editor (oder auch programmatisch von der Kommandozeile aus) bedienen, jedoch bietet das Icinga-Web Frontend einige LConf-spezifische Features, die einem die Verwaltung noch einfacher machen (z.B. besondere Suchfunktionen, Operationen über Verbindungen hinweg, Export der Konfiguration vom Frontend aus, etc. ). Zusätzlich gibt es noch LConf-Web – eine standalone Version die keine vorherige Icinga-Web Installation benötigt.

Das Frontend: Spezifische Dialoge für alle Objekttypen
Die auffälligste Neuerung in der Version 1.3 sind ( neben einer Menge Bugfixes) zahlreiche objektspezifische Dialoge, die einem bei der Konfiguration unterstützen. Jedes LConf spezifische Objekt hat jetzt eine eigene Eingabemaske, die einem bei der Arbeit unterstützt (wer lieber direkt mit den LDAP Attributen arbeitet, kann das jedoch immer noch).
Hier spare ich mir die Worte und lasse einige der neuen Dialoge für sich sprechen:
         
Zusätzlich gibt es natürlich die bewährten Features: Aliaserstellung/Aktualisierung, einfaches Arbeiten mit Drag&Drop, serverübergreifende Operationen, Export aus der Oberfläche, bequeme Filter- und Suchfunktionen, uvm.
Das Modul samt Doku und Bugtracker ist wie immer unter netways.org zu finden. Die Standalone Version vom LConf-Web ist derzeit noch in Bearbeitung, folgt aber in den nächsten Tagen.
Das Backend: Schneller und aufgeräumt
Im Backend hat Tobias zahlreichen Bugs den Garaus gemacht und nebenbei viel von der Codebasis aufgeräumt und umgeschrieben. Das Ergebnis kann sich sehen lassen: Neben kosmetischen Änderungen bietet Version 1.3 einen viel schnelleren Export und jetzt auch die Möglichkeit, Templates in die Vererbung mit einzubeziehen.
Obwohl letzteres wohl eines der gefragtesten Features im LConf ist, beeinflusst es doch das Ergebnis des Exportes stark. Aus diesem Grund ist das Feature standardmäßig Deaktiviert und die 1.3. Version als RC Version gekennzeichnet.
Das heisst: Die  Version ist zwar stabil, kann durch das ggf. andere Verhalten jedoch ein anderes Ergebnis als die Version 1.2 im Export liefern, sollte man das Vererbungsfeature Scharf schalten. Das sollte aber nicht vom Herunterladen und Verwenden abhalten (eher ermutigen!) – ein Blick in die Dokumentation schadet dabei aber nie.

JavaScript OO Features: Warum in die Ferne schweifen, das Gute liegt so nahe!

Stellen wir uns vor, Webentwickler würden anstatt Programmiersprachen Fremdsprachen sprechen: Englisch könnten wir, aber Französisch brauchen wir jetzt leider für unser neues Projekt.
Ganz logisch: Das mit den lateinischen Buchstaben kennen wir ja bereits, syntaktische Schnörksel wie Gravis sind unnötiger Codesmell und allgemein ist die Grammatik ja ziemlich komisch (bestes Beispiel “Grand Prix Eurovision de la Chanson Européenne” – das ist doch viel mehr Tipparbeit als Eurovision Song Contest und sagt das gleiche). Also nimmt man doch lieber alles was man nicht kennt aus der Sprache raus und erfindet seine eigenes, smarteres Französisch, das halt französische Wörter nimmt, aber vom Aufbau an Englisch angelehnt ist. Englisch ist ziemlich bekannt und ausserdem genauso feature complete, das macht die Sache für andere auch einfacher. Und für die Franzosen (die nicht in der Lage sind, unser besseres Französisch zu sprechen) schreibt man dann bei der eigentlichen Kommunikation einfach das schnieke Französisch 2.0 in das bloated Französisch 1.0 um, damit die auch was verstehen.
Klingt komisch? Willkommen in der Welt von JavaScript. Nach CoffeeScript hat jetzt Microsoft seinen Entwurf für ein ‘besseres’ JavaScript herausgebracht. Hauptargument: Vererbung und Objekte in JavaScript sind ja schwer zu handeln. Leider stimmt das seit ECMAScript 5 dank Object.create nicht mehr ganz (und das wird mittlerweile von einer ganzen Reihe Browser unterstützt), nur ist es da anders als man es gewohnt ist. Daher ein kleiner Exkurs in ECMAScripts ‘neue’ Objektmethoden:
Die Methode:

Object.create(parent,properties)

Erstellt in ECMAScript 5 ein neues Objekt,d das von parent erbt und die Eigenschaften aus properties besitzt. Z.b. würde:

 var Hund = Object.create(Animal,{ name: { value: 'Hund', writable: false } }) 

Ein Objekt Hund erstellen, das von Animal erbt und “Hund.name” würde einfach “Hund” zurückgeben. Was jetzt wirklich neu ist: Durch das writable: false werden sämtliche Versuche, Hund.name zu überschreiben ignoriert. Es gibt neben value und writable aber noch weitere praktische Attribute, nämlich:

  • enumerable: Gibt an ob die Eigenschaft bei einer for..in Schleife über das Objekt erscheint
  • get: Sehr praktisch: Ruft eine Funktion beim lesenden Zugriff auf die Eigenschaft auf, anstatt einfach nur einen wert zurückzugeben.
  • set: Ebenfalls praktisch: Ruft beim schreibenden Zugriff auf die Eigenschaft eine Funktion auf, anstatt einfach den Wert in die Eigenschaft zu schreiben
  • configurable: Definiert, dass die Konfiguration der Eigenschaft nicht verändert werden darf
Mit Object.defineProperty(objekt,name,properties) kann man auch nachträglich Eigenschaften an ein Objekt hinzufügen (z.B. für komplexere Methoden).

Man sieht also gleich, dass es hier ganz neue Sprachfeatures und nicht nur syntaktische Neuanordnungen gibt. Die sind zwar nicht ganz das sind, was man von der Objektorientierung her kennt (wo ist das ‘class’ Schlüsselwort?), aber JavaScript ist halt auch kein Java.
Zusätzlich dazu gibt es noch zwei praktische Methoden um Änderungen an Objekten zu verhindern:

  • Object.preventExtensions(Hund): Verhindert, dass man mit defineProperty Eigenschaften nachträglich an Hund hinzufügt
  • Object.seal(Hund) : Hier könnte man die Objektstruktur von Hund nicht mehr verändern
  • Object.freeze(Hund) : Hier kann man auch vorhandene (und auf writable gesetzte) Eigenschaften des Objektes nicht mehr ändern

Die Features werden von allen neueren Browsern (IE9+,FF4+, Chrome 5+, Opera 11.60+) unterstützt, für ältere gibt es bei Modernizr einen Polyfill.
Ich finde zwar z.B. Typescript eine ganz nette Sache und wirklich gut gemacht (gerade für JS Neulinge aus der Java/C# Welt). Allerdings würde ich persönlich mir wünschen dass mehr Energie in die bessere Unterstützung von ‘echtem’ JavaScript in IDEs gesteckt wird, anstatt andauernd das Rad neu zu erfinden. Am Ende interpretieren die Browser dann doch JavaScript – und das ist jetzt nicht so komplex oder aufwändig als dass man auf Zwischeninterpreter angewiesen ist um ein Projekt In-Time durchzubekommen. Immerhin gibt es auch gute (und kleine!) Bibliotheken, die einem das Leben erleichtern, wenn die Sprache einem doch Probleme bereitet.
Wer mehr zu den Objekt.* Methoden lesen will:

JavaScript Memory Leaks mit Chrome lokalisieren

JavaScript ist ja bekanntlich eine Sprache, die ihre Speicherverwaltung an einen Garbage Collector übergibt und dem Programmierer hier ein weitgehend unbeschwertes Leben verschafft. Meistens.
Wer bereits in anderen GC-basierten Laufzeitumgebungen wie Java programmiert hat, der weiß sicher dass auch ein Garbage Collector Memory Leaks in manchen Fällen nicht verhindern kann wenn der Programmierer unachtsam ist. Sobald ein Objekt nämlich noch in einem aktiven Bereich referenziert wird, bleibt er bis zum entfernen dieser Referenz im Heap (immerhin besteht die Möglichkeit, dass man das Objekt noch verwendet). Das Gute: Die meisten Memory Leaks sind so unbedeutend, dass man sie getrost ignorieren kann. Kritisch wird es erst, wenn man viele größere Objekte (z.B. DOM Knoten) über einen langen Zeitraum erstellt und entfernt, auf die aber noch in irgendwelchen Codeecken verwiesen wird (z.B. in einem Array). Dann gibt es auch in JavaScript irgendwann eine OutOfMemoryException – und ohne die richtigen Tools ist deren Ursache schwer aufzufinden (immerhin kann der Bereich z.b. in einem Closure liegen).
(more…)

Effiziente Codeorganisation in JavaScript: require.js

Dilemma:

Codeorganisation in JavaScript geht mir schon seit je her etwas auf die Nüsse. Wegen der Natur von JavaScript muss man entweder alle Skripte von Anfang an laden (= viel JavaScript parsen bei Seitenaufbau) oder man verwendet XHR/JSONP (JSONP ist in diesem Falle einfach ein dynamisches Einfügen von script Tags), was wiederum aufwendig ist, da asynchron. Eine include/import Direktive wie in anderen Sprachen existiert nicht.

Lösungsmöglichkeiten:

Netterweise haben sich viele (hauptsächlich Framework-) Entwickler ebenfalls schon Gedanken über Codeorganisation und dieses Problem gemacht und verschiedene Ansätze, teils recht ähnliche Ansätze entwickelt :

  • ExtJS hat eine recht feste Ordnervorgabe, an der sich die Anwendung orientiert. Dependencies müssen aber in den Klassen angegeben sein
  • Qooxdoo erkennt Abhängigkeiten automatisch, dafür muss man allerdings das Generator Skript bei Änderungen ausführen (entspricht daher in etwa dem klassischen Kompilieren/Linken)
  • CommonJS spezifiziert einen Standard für Modularisierung, der recht verbreitet bei Serveranwendungen ist (z.b. NodeJS, CouchDB)
  • Und last but not least (es gibt natürlich noch mehr) hat Dojo ihren Modularisierungsmechanismus AMD (Asynchronous Module Definition) getauft und mit require.jseine Implementierung zur Verfügung gestellt

Ich fand require.js den schönsten Ansatz wenn man gerade kein großes Framework verwenden will. Einerseits ist es recht schlank, benötigt wenig Setup und reduziert vor allem die Anzahl der globalen Browser-Objekte. Letzteres ist vor allem wichtig, wenn man Gefahr läuft zwei Versionen der gleichen Bibliothek verwenden zu müssen (weil man z.B. JQuery verwendet und ein Tool in die Applikation einbindet, das seine eigene JQuery Version mitliefert). Ausserdem ist AMD keine Insellösung, sondern basiert in weiten Teilen auch auf CommonJS.

Require.js – How To:

Die Einbindung von require.js ist recht einfach, man bindet einfach require.js ein und gibt optional an, welches Skript die Startlogik für die Applikation beinhaltet:

<script data-main="include/app.js" src="scripts/require.js"></script>

Jetzt wird beim Start direkt die Datei include/app.js eingebunden und ausgeführt.
(Man kann sehr einfach programmatisch auch noch extra Regeln für die Auflösung von Skripten, Grundpfade, etc. angeben, da verweise ich mal auf die gute Dokumentation)
AMD definiert jetzt zwei wichtige Funktionen: require() und define():

  • require() fordert require.js auf, erst die Module zu laden und mir danach bereitzustellen. Das kann z.B. so aussehen:

    require(["mein/modul1","mein/modul2"], function(modul1,modul2) {
    //hier kann jetzt mit modul1 und modul2 aus dem 'mein' Ordner (= Namespace) gearbeitet werden
        modul1.process(document.body);
    });

    So könnte jetzt unsere app.js aussehen und schonmal alle Module laden, die sie direkt benötigt. Nützlich ist das auch wenn man nur in speziellen Fällen eine Abhängigkeit braucht und diese nur bei Bedarf on-the-fly nachladen will. Ansonsten findet man sich häufiger dabei define() zu Verwenden:
  • define() definiert ein neues Modul und deren Abhängigkeiten. Die mein/modul1.js könnte jetzt so aussehen und z.B. JQuery und ein weiteres Modul benötigen (Achtung: $ ist nur eine Variable die auf JQuery zeigt, nichts besonderes.) :
     define(['lib/jquery','mein/modul3'],function($,modul3) {
        // Schnittstelle für modul1 wird zurückgegeben, hier z.B. ein Schnittstellenobjekt
        return {
           funktion1: function(el) { return modul3.process($(el)); } //tue irgendetwas mit dem element
        }   
    });

Für einfache Projekte braucht man oft auch gar nicht mehr – das Problem mit der Codeorganisation ist gelöst! Allerdings lohnt ein Blick in die Dokumentation, die ist wirklich sehr gut und bietet Anreize und Lösungen für viele Probleme, die im Alltag auftreten könnten.
Ein Nachteil an require.js ist natürlich, dass man sein Programmiermodell ein wenig Umstellen muss. Da der Aufwand jedoch nicht wirklich groß, der Nutzen jedoch schon ist, kann man das meiner Meinung nach verkraften.

Urlaub mit JavaScript

Der Mai ist schon furchtbar Neben andauernden Wechsel zwischen Kalt und Warm, Blütenstaub (gefürchtet bei Allergikern und Autobesitzern ohne Garage) und Baumarktwerbungen bringt er uns vor allem eins –  Feiertage und freie Zeit.
Wer kennt die Situation nicht: Im Haushalt gibt es nichts zu tun, die Fussballstadien sind abgebrannt und bei dem sonnigen Wetter hat man gar keine Lust zu Grillen, Sport zu treiben oder einfach nur das Leben fernab der Arbeit zu genießen. Doch JavaScript kann da helfen, nicht in ein tiefes Loch zu fallen.
Denn hier gibt es einiges, dass man sich mal anschauen sollte. Mein heutiger Blogpost ist daher eine kleine Auflistung interessanter Bibliotheken und bemerkenswerter Entwicklungen rund um JavaScript. Auf Details gehe ich dabei heute nicht ein, man kann das eher als eine Art Linkliste betrachten.

1. RaphaëlJS

RaphaelJS ist eine Bibliothek, die einem Entwickler erlaubt, browserübergreifend Vektorgrafiken und Visualisierungen umzusetzen. Je nach Browser wird dabei SVG (alle guten Browser) oder VML (Internet Explorer bis Version 8) verwendet. Die Api ist schön, einfach und mit 90 KB  sehr schlank. Dank der MIT Lizenz kann es auch in kommerziellen Projekten eingesetzt werden.
Will man ein paar kleine Graphen einbauen, gibt es gRaphael, das mit winzigen 10 KB Kuchen-, Linien- und Balkendiagramme zeichnen kann.

2. JavaScript Deluxe: CoffeeScript

CoffeeScript ist eine Programmiersprache von JavaScript Entwicklern, die zwar begeistert von der Sprache aber frustriert von dessen Syntax waren. CoffeeScript wird zu (lesbaren und JSLint kompatiblen) JavaScript interpretiert, welches dann im Browser ausgeführt werden kann. Dadurch kann es mit existierenden Bibliotheken verwendet werden und benötigt keine Plugins oder bestimmte Browser.
Die Sprache an sich erinnert ein wenig an Python, es gibt z.B. keine Klammern und keine Semicolons, dafür aber viele nützliche Sprachelemente. Sollte man sich auf jeden Fall mal anschauen, gerade wenn man mit JavaScript bisher nichts anfangen konnte oder aus der Python/Perl Ecke kommt.

3. HTML5Boilerplate

Das HTML5Boilerplate Projekt bietet ein (konfigurierbares) Standardtemplate für Webprojekte. Hauptziel ist es, eine solide, browserunabhängige Basis für neue Projekte zu schaffen. Das ganze ist also ausnahmsweise kein Framework oder irgendeine Bibliothek, sondern ‘nur’ eine Vorlage, die einem einen guten Projektstart ermöglicht, ohne in irgendeine Richtung zu zwingen.
Klingt lapidar, ist aber irre Praktisch und Zeitsparend. Jeder, der durch ein vergessenes “console.log” schonmal eine komplette Webanwendung im Internet Explorer abgeschossen hat, weiß was ich meine.

4. Abgefahrenes: pdf.js und jsmad

Hier kommt jetzt einfach nur interessantes, dass einem vor Augen führt zu was die aktuellen JavaScript Interpreter in der Lage sind: Pdf.js is ein komplett in JavaScript geschriebener PDF Viewer. Das Projekt ist zwar noch recht jung, funktioniert aber im Firefox und Chrome bemerkenswert gut. JSMad ist ein MP3 Player, der komplett in JavaScript geschrieben wurde, alac.js ist da gleiche, nur für das AAC Format (zum Teil in CoffeeScript geschrieben).
Wirkliche Geheimtipps sind da jetzt nicht dabei, aber vielleicht kennt jemand das ein oder andere ja noch nicht.

Große Dateien mit der JavaScript File-Api verarbeiten

Die JavaScript File-Api ist für mich (zusammen mir der Drag&Drop Api) etwas, das gemischte Gefühle erzeugt. Es ist unheimlich praktisch, Dateien clientseitig Einlesen und Verarbeiten zu können. Trotzdem  hat sowohl die Schnittstelle, als auch deren Implementierung ein paar Strickfallen, vor allem wenn die Dateigröße keine Rolle spielen soll.
Ein kleines Beispiel:
Ein einfaches Beispiel der File-API habe ich mal in jsfiddle zum ausprobieren angelegt. Hier sieht man schnell, wie man Dateien in der File-Api einliest, um sie später verarbeiten zu können
Folgende Funktion wird aufgerufen, wenn eine Datei ausgewählt wird:
var uploadHdl = function(ev) {
   var input = ev.target;
   var fileToRead = input.files[0];
    //neuen Reader erzeugen
    var reader = new FileReader();
reader.addEventListener("load",function(loadEv) {
      // hier liegt ein ArrayBuffer mit dem Dateiinhalt und
      // kann weiterverarbeitet werden
      alert("Datei eingelesen: "+loadEv.target.result.byteLength+" bytes");
})
reader.readAsArrayBuffer(fileToRead);
}

Und bis hier gibt es auch noch nicht viel an der Schnittstelle zu meckern, ausser vielleicht dass der FileReader keine Information in seinem onload event mitgibt, welche Datei er gerade gelesen hat. Daran geht die Welt aber nicht unter.
Was mich persönlich allerdings stört, ist dass das obige Beispiel nicht skaliert: Verwendet man eine Datei mit mehreren 100 mb oder sogar ein paar GB, sollte man in Deckung springen: Der Browser wird es nicht überleben.
(more…)

HTML/JavaScript Features, die auf jeder Party gut kommen

Heute werde ich Ausnahmsweise keine Benchmarks präsentieren (ok, einen halben), sondern eine kleine Ansammlung von JavaScript/HTML Features mit denen man gut bei seinen Freunden angeben kann:
1. CORS – Cross Origin Resource Sharing
Browser unterliegen der Geheimhaltungspflicht, d.h. Asynchrone Anfragen dürfen nur an die gleiche Domain gehen, auf der das Script liegt. Das ganze heißt ‘same-origin-policy’ und ist ein wichtiger Sicherheitsaspekt.
Führe ich auf meinem lokalen Webserver z.b. folgenden Code aus:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.netways.de', true);
xhr.onreadystatechange = function () {
/* ... hier wird die Antwort des Servers bearbeitet ... */
};
xhr.send(null)

Macht mir mein Browser gleich einen Strich durch die Rechnung:
“XMLHttpRequest cannot load http://www.netways.de/. Origin http://localhost is not allowed by Access-Control-Allow-Origin.”
Was aber wenn ich z.B. eine Api habe (wie z.B. Icinga-Web) und möchte diese von einer externen Webanwendung ansprechen (wie es z.B. icinga-mobile macht)?
Hier ist die Situation nicht ganz Ausweglos:  Der W3C hat hierfür CORS definiert. Bei obiger Anfrage macht der Browser nämlich mehr, als nur festzustellen ob origin == requestOrigin und wenn nicht einen Fehler zu werfen. In einem Netzwerksniffer würde man sehen, dass zuerst ein OPTIONS Request an den Server geschickt wird (der sogenannte Preflight).
Will der Server erlauben, dass externe Webanwendungen darauf zugreifen, kann er darauf Access-Control Header zurückschicken, z.b:

Access-Control-Allow-Origin: http://localhost
Access-Control-Max-Age: 2520
Access-Control-Allow-Methods: GET, PUT, DELETE, XMODIFY

Dies würde Seiten, die auf der Domain localhost laufen erlauben, den Server (der auf einer anderen Domain liegt) via GET, PUT, DELETE und XMODIFY anzusprechen. Der Max-Age Header gibt an, dass erst nach 2520 Sekunden ein neuer Preflight gestartet werden muss (ansonsten würde der Browser vor jeder anfrage einmal UPDATE anfragen und auf Antwort warten). Will man hier Cookies verwenden, muss man den allow-credentials Header auf true setzen – dann ist es jedoch nicht mehr möglich, eine Wildcard für den Origin zu setzen.
2. Seiten offline verfügbar machen – Manifest Files
HTML5 hat das html tag um ein Attribut bereichert: manifest.  Frech wie ich bin, klau ich mir jetzt einfach das Beispiel vom W3C:
Man hat z.B. eine einfache Webapplikation mit drei Komponenten: clock.html, clock.js, clock.css, die eine Uhr anzeigen (Ohne ntp, sondern nur lokal).
Will jemand ohne Netzverbindung die Seite aufrufen (auch wenn er Sie schonmal gesehen hat), bekommt er höchstwahrscheinlich eine Fehlermeldung, bzw. eine 404 Exception. Mit HTML5 kann man da ganz einfach sagen, dass bestimmte Teile nach dem Besuch der Seite auf dem Client gespeichert werden sollen, und später auch ohne Netzverbindung lokal verwendet werden können. Dafür definiert man eine einfache Datei mit beliebigen namen, hier clock.appcache, und legt sie neben der clock.html ab.
Der Inhalt besteht aus allen Dateien, die lokal gespeicher werden sollen (so ein Manifest kann eigentlich noch viel mehr, aber das würde den Rahmen hier sprengen)

CACHE MANIFEST
clock.html
clock.css
clock.js

Jetzt erweitern wir einfach das HTML Tag unserer clock.html seite mit
<html manifest=”clock.appcache”>
..und fertig – bei einem HTML5 kompatiblen Browser werden beim ersten Aufruf der Seite alle benötigten Dateien beim Client zwischengespeichert und können so auch ohne Netzverbindung verwendet werden.
3. Deferred scripts
(Ok, das ist jetzt nicht wirklich neu)
Der einzig wahre Ort für externe Skripte sollte im Head Bereich des HTML liegen. Doch was wenn das parsen eines Skriptes viel Zeit benötigt und deswegen den Aufbau der kompletten Seite bremst (obwohl es eventuell erst zu einem späteren Zeitpunkt benötigt wird)?
Für solche Fälle kann man dem Browser mit dem Attribut ‘defer’ einen Hinweis geben, dass ein Skript erst nach vollständigem Laden der Seite geparsed werden soll:
<script src=”slowscript.js” defer> </script>
Zugegebenermaßen hält sich der praktische Nutzen dessen oft in Grenzen (vor allem da defer nur für Skripte gilt, die nicht auf den DOM Baum zugreifen), im ein oder anderen Extremfall kann es dennoch sehr nützlich sein.
Der Standard definiert zusätzlich noch ein async Attribut, das ein Skript nebenläufig ausführt. Die Implementierung war bei meinen Tests anscheinend noch nicht vollständig, zumindest gab es keinen Unterschied zu defer.
4. Error Objekte:
JavaScript besitzt laut dem ECMA-262 Standard ein Error Objekt, das in den meisten Browsern auch verwendet wird. Anstatt wild irgendwelche Strings zu throwen, kann man so einfach eine der Error Klassen feuern (oder erweitern).
Leider besitzt JavaScript aber keine Möglichkeit, nur spezielle Error-Typen in einem catch() statement zu fangen, das feststellen ‘welcher’ Error gefeuert wurde wird einem damit also nicht auf Sprachebene abgenommen.
Ich habe jetzt zwar nicht wirklich Geheimnisse verraten, vielleicht ist für den ein oder anderen aber ja was neues dabei.

JavaScript Performance: Warum 'nativ' nicht immer besser ist.

Eigentlich wollte ich den heutigen Artikel neuen JavaScript Array-Features widmen, die am kommen oder schon da sind (forEach(), indexOf(), Iteratoren, Generatoren, etc.). Garnieren wollte ich das ganze mit ein paar Benchmarks, um bestenfalls zu zeigen dass die ‘nativen’ Arraymethoden der Browser meine selbstgeschriebenen Equivalente vor Neid erblassen lassen und was die Zukunft bringt. Doch das wäre wohl zu einfach gewesen…
Das Ergebnis war überraschend: Während meine Benchmarks im v8 (d.h. die JS-Engine von Chrome) zwar zeigten, dass manche meiner Methoden nur einen kleinen Tick langsamer waren (manche aber auch schneller), war es bei Spidermonkey (die Firefox engine) genau umgekehrt: Sobald dort die Tracing Engine aktiviert war (was Standard seit FF > 3.5 ist), lief mein eigener Code mit einer viel besseren Performance (z.T um den Faktor x6) als die ‘nativen’ SpiderMonkey-Methoden, die in C++ geschrieben waren.

Was komisch klingt liegt an der Art und Weise wie Fuchs optimiert: Mein eigener Code wird zur Laufzeit ge’traced’ (grob gesagt: Es wird verfolgt, ob die Typen der Variablen gleichbleibend sind und dementsprechend wenn möglich auf Typkonvertierungen und -überprüfungen verzichtet – wer Details will findet eine gute Einführung im Mozilla Blog ). Dementsprechend werden bei meinem selbstgeschriebenen Code weniger Operationen pro Durchgang benötigt. Bei den nativen Methoden ist dass anscheinend anders: Eine kleine Wanderung in den C++ Code von Spidermonkey zeigte, dass z.B. die Array.prototype.every() Methode Typen immer überprüft und konvertiert und ich schätze, dass hier derzeit kein Tracing stattfindet.
Die größten Performancesprünge lagen dabei interessanterweise bei Methoden, die Funktionen als Argumente nehmen, wie z.b. Array.map(), Array.filter(), Array.forEach().
Hier noch mein Benchmark zum selber Ausprobieren. Natürlich ist das immer ein Szenario und deckt damit nicht jeden Fall ab – ein anderer Benchmark kann ein völlig anderes Ergebnis liefern, ein neuerer Browser andere Werte, etc. Ich habe die Funktionen was Argumente und Verhalten angeht nachgeschrieben, allerdings ist ein 1:1 Vergleich immer schwer und das Szenario (wie bei einem Benchmark üblich) natürlich extrem (10000 Elemente im Array und 1000 Durchgänge).
Das eigentliche Fazit: Gerade bei neuen Methoden wie den JavaScript 1.6+ Array Funktionen, die nicht bei jedem Browser vorhanden sind sollte immer erst geprüft ob sich der Aufwand lohnt, oder ob man auf ‘konservative’ Methoden zurückgreift. Cross-Browser-Kompatibilität erfordert immer Mehraufwand, und dieser wird nur gerechtfertigt wenn unterm Strich ein Mehrwert herauskommt. Und darauf will ich hinaus: Wir Webentwickler werden zwar einige neue Features wie Iteratoren und Generatoren bekommen (Firefox unterstützt diese auch schon bereits) – trotzdem ergibt es oft Sinn, lieber auf Helferfunktionen von Core-Toolset wie Prototype, JQuery oder ExtJS zu setzen, die browserübergreifend die selben Funktionalitäten anbieten. Die ‘neueren’ Methoden sind  a) nicht in jedem Browser vorhanden, und b) evtl. sogar langsamer, oder nur minimal schneller – womit sie derzeit für den Produktiveinsatz ausscheiden.
Ich will hier natürlich keinen Fortschritt aufhalten: Es ist gut, dass sinnvolle Hilfsmethoden wie filter() oder map() Einzug in den Standard finden und ich werde sie sicher auch selbst nutzen wenn Sie verbreitet genug sind. Allerdings sollte man für den Produktiveinsatz eher mit geschärften Bewusstsein an neue (Sprach-)Features wagen.

Low-level memory access in JavaScript: Typed arrays.

Interessante, aber eher unbekannte (da sehr neue) Datentypen in JavaScript  sind der ArrayBuffer und Typed Arrays. Diese Datentypen wurden in erster Linie eingeführt um effektiv auf Binärdaten zugreifen zu können.
Grundlage für alles ist der ArrayBuffer, ein einfacher Datentyp, den man beim Erstellen mitteilt wie viele Bytes er belegen soll. Das besondere ist dass dieser ArrayBuffer an sich keine Möglichkeit besitzt gelesen oder beschrieben zu werden (auch wenn die Spezifikation einen Proposal für eine ‘splice’ Methode hat). Hier kommen die Typed Array Datentypen (oder wie in der Spec: Views) hinzu. Diese ermöglichen es dem Speicher eine logische Aufteilung zu geben, z.B. als ein Array von 32-Bit großen Floats im Falle von Float32Array:
var buffer = new ArrayBuffer(8); // 8 Byte im speicher reservieren
var floatBuffer = new Float32Array(buffer); //floatBuffer ist jetzt ein Array mit 2 elementen (8*8/32 = 2)
floatBuffer[0] = 0.255315; // ab hier gibt es kaum einen Unterschied zu einem normalen js array, ausser dass indexüberlaufe einfach ignoriert werden
floatBuffer[1] = 0.3535;

Der Nutzen ist, dass man mit JavaScript nun effektiv mit binären Daten arbeiten kann. Davor musste man Binärdaten als String darstellen, mit charCodeAt Byteweise auslesen und Datentypen wie Floats und Integers ebenfalls aus Byteblöcken zusammenbauen.
Mich hat allerdings eher interessiert, wie sich die Performance von ‘normalen’ Operationen auf Arrays verhält, wenn man das JavaScript Array Objekt mit dem ArrayBuffer austauscht. Mein Benchmark dafür ist sehr einfach:

for(var i=0;i<size;i++) {
    container[i] = Math.random();
}
var sum = 0;
for(var i=1;i<size;i++) {
sum += container[i];
}
var avg = sum/size;

Ich fülle hier einfach ein Array ‘container’ (welches wahlweise ein ArrayBuffer oder ein Array Objekt ist) mit Zufallswerten und berechne anschliessend den Durchschnitt. Das ganze habe ich auf meinem MacBook Pro 13″ (i5 2,3Ghz) mit ‘size’ von 21 bis 225 einmal im Chrome 14 getestet und einmal im Firefox 6. Die Ergebnisse in bunt (Die Elemente mit 0 ms habe ich mal herausgelassen):

Man sieht ganz klar, wie die Performance des internen Arrays ab ca. 65536 Elementen ausreisst (vor allem im Chrome), während das Float32Array recht linear skaliert. Bei sehr großen Datenmengen lohnt es sich also, mal ein Float32Array -wenn vorhanden- auszuprobieren. Einen Nachteil haben die BufferArray Objekte allerdings: Das erstellen ist aufwändiger als bei internen Arrays. Generell sollte man immer die Performance messen und schauen, ob man wirklich einen sinnvollen Geschwindigkeitsbonus durch Typed Arrays bekommt – mein Benchmark hat keinen Anspruch auf Allgemeingültigkeit.
Fazit: JavaScript kann jetzt endlich effektiv mit größeren und binären Datenmengen umgehen. Man muss zwar entscheiden, ob sich der Aufwand lohnt – immerhin muss man, will man kompatibel zu älteren Browsern bleiben, eine Fallback-Variante anbieten. In Kombination mit WebSockets und der File Api eröffnen sich aber ganz neue Möglichkeiten (wie z.B. pdf.js, das PDF direkt in JavaScript rendert).

Wenns mal wieder länger dauert – PHP Profiling mit KCachegrind

Beim Entwickeln von Software gilt oft der Grundsatz “Arbeitszeit ist teurer als Rechenzeit”. Was bringt es mir, wenn eine nicht performancekritische Anfrage 100ms schneller ausgeführt wird, das Projekt durch den Optimierungsaufwand aber in Verzug kommt?
Das Problem hierbei ist allerdings die Definition von “performancekritisch”. Projekte wachsen, Anwendungsumgebungen werden größer und was Anfangs eine “nicht kritische” Methode war, bremst jetzt auf einmal die komplette Anwendung. In so einem Fall das Performanceleck zu finden kann schwierig werden – bei PHP können einem allerdings Tools wie XDebug und KCachegrind helfen.
Das Setup ist sehr einfach, einfach php5-xdebug installieren, in der xdebug.ini (oder der php.ini)
xdebug.profiler_enable=1
hinzufügen, ggf. den Webserver neu Starten und schon werden cachegrind Files im /tmp erzeugt.
Zum visualisieren der Dateien kann man jetzt das Tool KCachegrind (oder am Mac z.b. QCachegrind) verwenden – schon sieht man schön übersichtlich, welche Methoden wieviel Zeit einnehmen (absolut oder relativ zur Ausführungszeit) und wo/wie oft diese aufgerufen wurden, usw.
Ausprobieren lohnt sich – gerade wenn man fremde Frameworks verwendet findet man so schnell Performancefallen ohne sich lang durch den Code zu wühlen.