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

Hallo Ihr =)

"ein skript auf dieser seite verursacht eine verzögerung...." Meldung im IE8 ->

Habe ein etwas größeres Skript gebastelt, es funktioniert auch genau so wie es soll, jedoch sind da viele Schleifen drin (Dank einiger 2D-Arrays die alle ausgelesen werden wollen)

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, und jedes TD (ja, ich weiss Boxmodell, aber hier hat es sich eben angeboten, da es auch als Tabelle dargestellt wird) beinhaltet nochmal Eventhandler mit Funktionen, onclick, onfocus, onchange, ondblclick.

Kann man diese Meldung irgendwie unterbinden im IE8 ohne an den Einstellungen zu schrauben? Irgendein Code a la <!-- saved from url=(0014)about:internet --> was die nervige Active-X-Warnung unterbindet?

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

Gruß

KillKenny

  1. Meine Herren!

    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, und jedes TD (ja, ich weiss Boxmodell, aber hier hat es sich eben angeboten, da es auch als Tabelle dargestellt wird) beinhaltet nochmal Eventhandler mit Funktionen, onclick, onfocus, onchange, ondblclick.

    Du musst die Event-Handler nicht bei jeder Tabellen einzeln registrieren, stattdessen kannst du einen Handler je Event am table-Element registrieren und mit event.target die betroffene Zelle ermitteln.

    Kann man diese Meldung irgendwie unterbinden im IE8 ohne an den Einstellungen zu schrauben?
    Oder bin ich gezwungen die eine große Funktion in viele kleine zu splitten?

    Weder noch, obwohl zweiteres sicherlich auch sinnvoll ist.
    Du musst das Problem an der Wurzel packen und das ist mangelnde Performanz. Die Aufgabe vor der du jetzt stehst, ist es den Flaschenhals zu ermitteln. Die Entwicklertools (STRG+Shift+I oder F12) bieten dafür Werkzeuge an. Mit ein paar Tutorials solltest du dich in die Lage versetzen können, dein Leck zu finden und zu schließen.

    1. Ok alle Eventhandler einfach mal entfernt, etwas schneller, jedoch immernoch die Warnung ... Ist wohl zu Umfangreich ^^"""

      Gibt es im IE oder FF eine Funktion mit der ich ne Art Benchmark durchführen kann? Aber ich denke, ich werde dann erstmal deinen Rat befolgen und die Events "auslagern" dann sind schonmal einige Zeilen gespart.
      Frage dazu: In den Events benutze ich oft "this....." kann ich weiterhin this. benutzen, oder muss ich alles ändern in zb getElementById? Sprich, bezieht er immernoch This. auf das Element, das den Eventhandler aufruft?

      Splitten muss ich dann wohl auch alles, Schade, hatte mir viel Mühe gegeben alles in eine Funktion zu schreiben, um eben Code zu sparen, ging wohl nach hinten los :-P

      Grüße

      1. Grrr.... Gerade gesehen, der Fehler kommt nur mit IE8, FF26 parst das alles innerhalb von 2 Sekunden .... Zu blöd das es aber eben auf IE8 laufen muss T_T ich weiss schon warum ich kein IE benutze....

        1. Hallo,

          Grrr.... Gerade gesehen, der Fehler kommt nur mit IE8, FF26 parst das alles innerhalb von 2 Sekunden .... Zu blöd das es aber eben auf IE8 laufen muss T_T ich weiss schon warum ich kein IE benutze....

          Dir ist schon klar, dass IE 11 aktuell ist? Als IE 8 erschien, war gerade Firefox 3.0 aktuell. Dass ein Performance-Vergleich zwischen IE 8 (März 2009) und Firefox 26 (Dezember 2013) ergibt, dass letzterer schneller ist, ist wenig verwunderlich.

          Mathias

      2. Meine Herren!

        Gibt es im IE oder FF eine Funktion mit der ich ne Art Benchmark durchführen kann?

        Ein Benchmark taugt nur begrenzt um dir die Schwachstellen deines Algorithmus aufzuzeigen.
        Die Firefox und Chrome Entwickler-Tools (STRG-Shift+I) haben den Profiler. Firebug für Firefox bietet auch was in der Art und der IE ab Version 9 (Öffnen mit F12) ebenfalls.

        Eine Benchmark-Suite gibt es z.B. bei jsPerf.

        Aber ich denke, ich werde dann erstmal deinen Rat befolgen und die Events "auslagern" dann sind schonmal einige Zeilen gespart.

        Mein eigentlicher Rat sollte gewesen sein, den Flaschenhals zu finden und da mit der Optimierung anzusetzen und nicht auf gut Glück irgendwelche Lecks zu stopfen.

        Frage dazu: In den Events benutze ich oft "this....." kann ich weiterhin this. benutzen, oder muss ich alles ändern in zb getElementById? Sprich, bezieht er immernoch This. auf das Element, das den Eventhandler aufruft?

        this würde in dem Fall auf das table-Element zeigen, bei dem du den Event-Handler registriert hast. Um an die Tabellen-Zelle zu gelangen müsstest du event.target benutzen (event wird dem Handler dabei als Parameter übergeben, für alte IEs ist event global). Das Prinzip von dem du Gebrauch machst nennt sich Event-Delegation.

        Splitten muss ich dann wohl auch alles, Schade, hatte mir viel Mühe gegeben alles in eine Funktion zu schreiben, um eben Code zu sparen, ging wohl nach hinten los :-P

        Mach sowas doch nicht. Dein Ziel sollte es immer sein möglichst ausdrucksstarken Quelltext zu schreiben. Um die Prgramm-Größe zu verkleinern gibt es Werkzeuge, die sich minifier oder uglyfier nennen und automatisiert so viel schrumpfen, wie du es per Hand nie könntest.

        --
        “All right, then, I'll go to hell.”
        1. Hallo 1UnitedPower,

          ... Um die Prgramm-Größe zu verkleinern gibt es Werkzeuge, ...

          die den Code aber nicht schneller machen.

          @KillKenny
          Lange laufende Scripte lassen den Browser einfrieren, daher die Warnung. Wenn Optimierung nicht helfen, bleibt dir nur, das Script in Teile zu zerlegen und diese mit setTimeout nacheinander laufen zu lassen. Dadurch bekommt der Browser immer wieder die Kontrolle und kann auf Benutzereingaben reagieren und friert nicht ein.

          Gruß, Jürgen

  2. 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