molily Navigation

JavaScript-Profiling über benannte Funktionsausdrücke

Juriy Zaytsev, seines Zeichens Mitentwickler des Prototype-JavaScript-Frameworks, hat einen tollen (englischsprachigen) Artikel über Funktionen in JavaScript und im speziellen benannte Funktionsausdrücke geschrieben:

Named function expressions demystified

Nicht nur gibt er eine Einführung in die möglichen Notierweisen von Funktionen - Deklarationen versus Ausdrücke -, sondern diskutiert auch den Nutzen von benannten Funktionsausdrücken und Browserfehler, die die Anwendung erschweren.

Warum sind benannte Funktionsausdrücke so sinnvoll? Bei neueren JavaScript-Pattern wie etwa Objektliteralen zur Strukturierung von JavaScript-Programmen verwendet man ständig Funktionsausdrücke. Objektliterale finden auch bei dem populären Module-Pattern Verwendung.

Ein paar Beispiele für Funktionsausdrücke in diesem Kontext:

var Modul = {
   methode : function () {
      // Funktionsausdruck
   }
};

var Modul = (function () { // Anonymer Funktionsausdruck
   var privateMethode = function () {
       // Funktionsausdruck
   };
   return {
      öffentlichePriviligierteMethode : function () {
         // Funktionsausdruck
      }
   };
})();

Aber auch bei der restlichen JavaScript-Programmierung werden ständig anonyme Funktionen notiert, etwa beim Event-Handling und in Form von Callbacks. Beispiel jQuery, in anderen Bibliotheken prinzipiell gleich:

jQuery("#element").bind("click", function (e) {
   // Funktionsausdruck
});
jQuery.get("/ajax", function () {
   // Funktionsausdruck
});
jQuery("#element")..fadeIn("slow", function () {
   // Funktionsausdruck
});

Bei Timeouts und Intervallen:

window.setTimeout(function () {
   // Funktionsausdruck
}, 1000);
var interval = window.setInterval(function () {
   // Funktionsausdruck
}, 1000);

Oder generell bei der funktionalen Programmierung, z.B. beim Verarbeiten von Arrays mit den neuen Methoden aus JavaScript 1.6 bzw. ECMAScript 5:

[1, 2, 3].forEach(function () {
   // Funktionsausdruck
});

Je weiter man in JavaScript eintaucht und je mehr man funktionale Bibliotheks-Schnittstellen nutzt, desto stärker nutzt man die Möglichkeit, während der Laufzeit Funktionen zu erzeugen. Oftmals wegen der Fähigkeiten von Closures.

Das Problem dieser namenlosen (anonymen) Funktionen ist, dass sie das Profiling von großen JavaScript-Anwendungen erschweren. Damit ist eine Statistik aller Funktionsaufrufe gemeint, bei der die Anzahl der Aufrufe sowie deren mittlere Laufzeit gemessen wird. Diese wichtige Methode zur Performance-Optimierung von JavaScripten ist beispielsweise mit der Firefox-Erweiterung Firebug und mit dem Web Inspector von Safari und Chrome möglich.

Ohne aussagekräftige Funktionsnamen sind die Messdaten eines Profils sehr schwer lesbar:

Firebug erlaubt es zwar, beim Klick auf den Namens-Platzhalter in den Quelltext zu springen, allerdings lässt sich die Verbesserung der Performance viel besser mit einem schnellen Überblick über alle Funktionen vornehmen.

Auch beim Debugging stellen anonyme Funktionen ein Problem dar: Bei Javascript-Fehlern zeigen Werkzeuge wie Firefox den Stacktrace an, das ist die Liste der verschachtelten Funktionsaufrufe bis zu dem Punkt, an dem der Fehler auftrat. Diese Stacktraces sind unverständlich, wenn die meisten Funktionen keine Namen besitzen und nur Codezeilen angegeben sind.

Wenn die meisten Funktionen Namen besitzen, dann ist ein aussagekräftiges Profiling möglich wie hier bei meinem JavaScript für das SELFHTML-Forum: