JavaScript Performance

Auch wenn der Blog sich vorrangig mit serverseitigen Optimierungen befasst, darf man ja die Client-Seite nicht außer Acht lassen. Deshalb heute ein kleiner Beitrag zum Thema JavaScript-Optimierung.

Inspiriert wurde ich durch einen Beitrag bei Dr. Web.
Es geht darum, inwiefern alte Konstrukte durch neuere – und vor allem performantere – Äquivalente ersetzt werden können.

Leider wurde keine der dort gemachten Empfehlungen durch irgendeinen Satz begründet, weshalb diese Varianten schneller sein sollen. Deshalb versuche ich das mal.

Punkt 1:

  //Alt: 
  element.onclick = new Function("..."); //Neu: 
  element.onclick = function("...");

Ehrlich gesagt habe ich das nie anders gemacht und auch in Fremdscripten nicht gesehen. Bei der oberen Variante wird eben ein Objekt angelegt, unten nur eine Funktion. Das Objekt ist speicherintensiver, deshalb wird die untere Variante empfohlen. Kann ich mich anschließen – aber wie gesagt: Das als ersten Punkt zu wählen, ist nicht so doll gelungen auf Grund der mangelnden Verbreitung.

2. Punkt:

  //Alt: 
  return eval("document.forms[0]." + field); 
  //Neu: 
  return document.forms[0][field];

Hier wird es schon sehr viel interessanter. Jeder ernsthafte Programmierer scheut eval – und das zu recht, weil dadurch immer wieder Sicherheitslücken entstehen. Überhaupt ist eval programmiertechnisch nicht sauber. Ich versuche es in 99% der Fälle zu vermeiden (auch wenn es manchmal etwas mehr Code bedeutet).
Aus Performance-Sicht macht obige Aussage ebenfalls Sinn, denn eval() ist eine Funktion, die den ihr übergebenen String zuerst parsen muss (gerade das ist ja die Schwachstelle, weil eval() alles Mögliche ausführen kann). Wieso aber sollte man eine Funktion aufrufen, wenn der gesuchte Wert bereits in einem vorliegenden Array zu finden ist? Genau, man sollte es nicht ????
Auch hier gilt mal wieder: eval ist evil.

Punkt 3:

  //Alt: 
  with(document.forms[0]) { alert(elements.length); 
  } 
  //Neu: 
  var form = document.forms[0]; alert(form.elements.length);
  

Die with-Schreibweise ist eine schön kurze Version, wenn man auf Attribute oder methoden eines bestimmten Objektes nacheinander zugreifen möchte. Nachteil dabei ist, dass dieses Objekt temporär im Speicher gehalten werden muss.
Der Tipp ist deshalb nur sinnvoll, wenn man nur eine einzige Anweisung innerhalb des with-Blocks ausführt. Aber dafür ist der Block ja eigentlich auch nicht geschaffen. Hat man mehrere Anweisungen auf ein Objekt auszuführen, denke ich, dass das with performanter ist, da dann das Objekt nicht jedes Mal neu in den Speicher geladen werden muss.
Beispiel:

  with(document.getElementById('id')) { style.color = "red"; innerHTML = "Hallo"; }

4. Punkt (auf der Tagesordnung):

//Alt: 
  try { ... } catch() { ... }  
  //Neu: 
  if() { ... } else { ... }
  

Dieses Beispiel verstehe ich nicht ganz, denn if-else und try-catch kommen eigentlich aus ganz verschiedenen Ecken (und haben deshalb auch unterschiedliche Aufgaben). Mit try-catch fängt man Fehler ab. Gut, man kann vorbeugend if-else benutzen (muss dann aber an wirklich alle möglichen Fehlerquellen denken). Also für mich 2 Paar Schuhe…

Punkt 5 (Variablen lokal setzen):

  //Alt: 
  var a, b = 1; 
  function test() { 
  var c = a + b;
  }   
  //Neu: function test() {
  var a, b = 1; 
  var c = a + b; 
  }

Gut, das ist aus zwei Gründen sinnvoll: Zum einen wird die Variable gekapselt. Dadurch kommt es nicht zu unerwünschten Überschreibungen. Außerdem muss für die Variable nur dann Speicher reserviert werden, wenn die entsprechende Funktion auch aufgerufen wird.
Prädikat: Besonders sinnvoll!

Punkt 6 (for-in-Schleifen):

  //Alt: 
  
  for (var i in array) {
  alert(array[i]); } 
  //Neu:
  var length = array.length;
  for (var i = 0; i < length; i ++) { alert(array[i]); }
  

Auch hier stimme ich zu. for-in-Schleifen sind nur sinnvoll bei Arrays, bei denen der Index nicht fortlaufend ist (also wenn man die Positionen der einzelnen Elemente selbst festgelegt hat).
Schön: Auch der Umstand, dass man vor der Schleifenbedingung schon die Arraylänge überprüfen sollte, damit diese nicht in jedem Durchlauf ermittelt werden muss.

Und noch einer:

//Alt:
setInterval("func()", 10000) 
setTimeout("func(" + value + ")", 10000);   //Neu: 
setInterval(func, 10000) setTimeout 
(function() {
     func(value)
}, 10000);

Dies ist mir neu gewesen, aber ich nutze auch recht selten solche Funktionen. Für AJAX sind sie manchmal wichtig, wenn man eine periodische Aktualisierung der Daten erreichen möchte, aber sonst eigentlich nur bei Spielereien wie Animationen oder Spielen.
Macht aber nichtsdestotrotz Sinn, da der String ja erst interpretiert werden muss vor dem Ausführen, während die Funktion direkt ausgeführt werden kann. Kann ich also auch empfehlen.

Was ich jetzt nicht geprüft habe, ist, ob diese Dinge auch in sämtlichen gängigen Browsern funktionieren. Ich denke aber mal schon…

Der letzte Tip ist natürlich immer gut: Alles, was vom Server geladen werden muss, sollte komprimiert werden. Spezielle JS-Komprimier-Tools können die Dateigröße siginifikant senken.

Ist es doch ein ganz schön langer Beitrag geworden. So war das nicht geplant, aber ich hoffe euch freuts ????


Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0