molily: ein skript auf dieser seite verursacht eine verzögerung

Beitrag lesen

Hallo,

Der größte Teil ist eine einzige Funktion (reines JS) das 2 Arrays ausliest mit jeweils 15 mal 65 Variablen und diese als Tabelle ausgibt

Hängst du jede Tabellenzeile/-zelle einzeln ins bestehende DOM? Das ist aus Performance-Sicht ungünstig.

Besser ist, die Tabelle als String oder DOM-Struktur im Speicher zu erzeugen und in einem Rutsch ans Dokument anzuhängen. Dieser Vorgang lässt sich optimieren, indem der HTML-Code bzw. die DOM-Elemente so performant wie möglich erzeugt werden (z.B. durch Event Delegation und den Verzicht auf Inline-Event-Handler).

Oder bin ich gezwungen die eine große Funktion in viele kleine zu splitten?

Das alleine bringt nichts.

Deine Operationen werden synchron ausgeführt und blockieren den Browser; ob das nun in einer großen oder vielen kleinen Funktionen passiert, ist nicht entscheidend.

Der Browser zeichnet die Seite erst, wenn JavaScript stoppt und die Ausführung zur Ruhe kommt. Wenn die Ausführung insgesamt zu lange dauert, sie man gar keine Seite und der Browser zeigt die Warnmeldung.

Um sowohl das Zeichnen zu beschleunigen als auch die Warnung zu vermeiden, kann man die Generierung der Tabelle in kleine Häppchen aufteilen, deren Ausführung durch Wartezeiten unterbrochen wird. Dieses »Warten« lässt sich mit setTimeout oder requestAnimationFrame umsetzen.

http://de.selfhtml.org/javascript/objekte/window.htm#set_timeout@title=setTimeout sorgt nicht notwendig für ein Zeichnen der Seite, unterdrückt aber die Laufzeitwarnung, da der aktuelle Ausführungs-Stack beendet wird und ein neuer begonnen wird. setTimeout(callback, 0) oder setTimeout(callback, 1) reicht hier aus. Speziell für den Fall gedacht ist übrigens setImmediate, aber das unterstützt derzeit nur der Internet Explorer und andere Browserhersteller lehnen es ab.

requestAnimationFrame sorgt dafür, dass der Browser eventuelle Änderungen am DOM umsetzt und die Seite neu zeichnet. Anschließend wird der Callback aufgerufen. Wenn du schnell etwas ausgeben willst (z.B. jede Tabellenzeile soll sofort gerendert werden), ist diese Methode hilfreich. Allerdings unterstützt sie IE8 noch nicht. Im IE8 würde ich einfach setTimeout mit einer höheren Wartezeit verwenden, um ihm Zeit zum Rendern zu geben, falls das denn gewünscht ist.

Wenn du vorher eine synchrone for-Schleife hattest, so kannst du jetzt eine asynchrone Schleife mittels Rekursion umsetzen:

var allData = [];  
var i = 0;  
var table = document.createElement('table');  
var tbody = document.createElement('tbody');  
table.appendChild(tbody);  
var addNextRow = function() {  
  var rowData = allData[i];  
  // … Erzeuge tr- und td-Elemente …  
  tbody.appendChild(tr);  
  i++;  
  if (i < allData.length) {  
    // Rekursiver, asynchroner Aufruf  
    setTimeout(addNextRow, 0);  
  } else {  
    // Hänge die Tabelle letztlich ins DOM  
    document.body.appendChild(table);  
  }  
};  
addNextRow();

Dieses Beispiel hängt die ganze Tabelle in einem Rutsch ins DOM, vorher wird also nichts zwingend gezeichnet.

Mathias