mmofacts.com

Performance beim Erzeugen von html Elementen mit Javascript

gepostet vor 16 Jahre, 3 Monate von MrMaxx

Ich entwickle an einem Spiel namens overwatch http://overwatch.de .

Dieses Spiel besteht aus einer Kartenansicht, in der alle Aktionen gemacht werden. Diese Kartenansicht beinhaltet viele DIVs, die hin und hergeschoben und vor allem erstellt werden müssen. Besonders das Umsetzen des sichtbaren Kartenausschnitts erfordert das komplette Neurendern der Elemente.

Ein sehr interessanter Artiken zum Thema Performance ist hierbei: "Benchmark - W3C DOM vs. innerHTML".

Nun erstelle und füge ich meine HTML Elemente mit der dort empfohlenen Methode ein. Ein PerformanceUnterschied wie Tag und Nacht (nie gemessen, rein subjetives Empfinden).

Davor: Prototype und Scriptaculous werden verwendet: var element = Builder.node(...); $('parentelementId').appendChild(element); .. das ganze mehrere hunter mal zwingt normale Rechner langsam in die Knie. Ganz beonders langsam wird es dann, wenn auf all diesen Elementen auchnoch Evenhandler angemeldet werden Event.observe( element, 'click', doSomething );

Jetzt: var elementArray = new Array(); myDataArray.each( function(date){ elementArray.push( createElement(data) );} ); $('targetElementId').innerHTML = elementArray.join('');

Wobei createElement auch gleich für Eventhandling das onclick Attribut setzt.

Eine Sache gibt es jedoch, auf die geachtet werden muss: Nachträglich etwas an das innerHTML anzuhängen ist (besonders bei vielen bestehenden Elementen im innerHTML) sehr unperformant, da Browserseitig alle DOM Elemente gelöscht und neu erstellt werden müssen. Daher hänge ich nachträglich einzelne Elemente wieder per appendChild an.

Wollt mal wieder was schreiben...

Maxx

gepostet vor 16 Jahre, 3 Monate von Nuky

Nebentipp: die einzelnen Elemente größer machen oder, je nach Individualisierung der Elemente, vorrendern!

Ich bin mal vorm selben Problem gestanden wie du. ;)

gepostet vor 16 Jahre, 3 Monate von Klaus

Ich konnte das soweit in den Griff kriegen in dem ich die Komplexität der Elemente so gering wie möglich gehalten hab. Also keine großen Verschachtelungen starten.

gepostet vor 16 Jahre, 3 Monate von HSINC

ist klar, bei der ersten methode renderte der browser nach jedem hinzugefügten element die seite neu. bei der zweiten methode passiert das eben nur einmal am ende.

man kann die sache durchaus auch mit parentelement.display:none . addelements(many). parentelement.display:whatever lösen

gepostet vor 16 Jahre, 3 Monate von Dunedan

Alternativ würde sich für so eine Anwendung eventuell Canvas eignen?

gepostet vor 16 Jahre, 3 Monate von KoMtuR

Versuche die elemente in ein node zu packen, der nicht angezeigt wird und danach diesen in das anzuzeigene Div zu kopieren. Offscreen-Rendering sozusagen. Bringt sehr viel Performance.

Also ich hoff du verstehst mich. Erst deine Karte in ein nicht angezeigten Container einfügen und dann mittels replaceChild den kompletten Container austauschen

edit: ach HSINC hats schon geschrieben ;)

Achja was mir noch einfällt. Die Karte wird ja statisch sein. Da vielleicht mehrere Blöcke unterteilen und die separat speichern. So das du nur die austauschst, die man wirklich sieht. Den Rest in einem Array aufbewahren und bei gebrauch dann von dort holen (dann musste aber auch mit cloneNode arbeiten, weil sonst irgendwann deine Blöcke verloren gehen)

edit2: das Event.observe machste am Besten so, dass du jedem eingefügten Element eine klasse gibst und dann einfach per selector diese Event anfügst (vorrausgesetzt die haben alle die gleiche Funktion zum abhandeln):

JavaScript:

  $$('#container div.piece').invoke('observe', 'click', doSomething);

Wobei das hier nur ne Beispielklasse "piece" in einem container mit der id "container" ist ;)

gepostet vor 16 Jahre, 3 Monate von MrMaxx

Hajo...ich bin mit meiner momentanen Version auch sehr zufrieden. Alle dynamischen Elementen, die sich auch verändern können werden jeweils neu gerendert (im Moment auch neu erstellt), während der statische Teil der Karte nach dem Erstellen der Karte als grosses png vorgerendert (z.B.  http://overwatch.de/level/1full.png plus Listenansichtsbild http://overwatch.de/level/1small.png) und dann im Hintergrund verschoben wird.

Meine gefühlte Performance messe ich immer an meinem 1GHz 512MB Laptop...wenns darauf angenehm läuft bin ich zufrieden und das tut es.

Maxx

gepostet vor 16 Jahre, 3 Monate von cherry

Ich denke auch, dass die vorgerenderten Bilder eine gute Loesung sind die DOM jongliererei auf ein Minimum zu beschraenken. Besonders wenn man eine statische Karte hat wie Du oder ne Karte die sich nur in bestimmten wohldefinierten Zeitintervallen (aka Ticks) aendert. Nicht nur das Erzeugen, Loeschen und bewegen wird einfacher und schneller sondern auch das Eventhandling.

Der Artikel ist sehr interessant - danker fuers Daraufhinweisen :-) Offscreen Rendering finde ich auch sehr interessant.

Dein Projekt sieht ziemlich cool aus ich habe es einmal ausprobiert. Leider verstehe ich nicht ganz wie es funktioniert, hehe. Aber cool aussehen tuts. Gibts ne Anleitung?

gepostet vor 16 Jahre, 3 Monate von MrMaxx

Im Moment arbeite ich am Spielinterface und muss danach die Anleitung eh neu besprechen...aber es gibt einen WIP:

http://overwatch.de/anleitung

MrMaxx

gepostet vor 16 Jahre, 3 Monate von cherry

Cool, danke! Wenn das mit den Browsergame-Millionen nicht klappt kannst Du zum Radio gehen finde ich :-)

gepostet vor 16 Jahre, 3 Monate von henna1

Hoppla, das sieht nach einem benötigten Captcha für Gäste aus ...

gepostet vor 16 Jahre, 3 Monate von TheUndeadable

Nene, das sind nur Tipps für verbesserte Performance in JavaScript ;-)

gepostet vor 16 Jahre, 3 Monate von Toby

Captcha mag ja fehlen, dafür gibts ein richtiges Ticketsystem hier...

gepostet vor 16 Jahre, 2 Monate von schokofreak

Hallo,

Interessantes Thema! Habe vor langem mal damit herumgespielt und einen Weg benutzt welcher meiner Meinung nach performanter war als InnerHTML.

Schau doch mal was passiert wenn du die DOM Objekte bottom-up erstellst? Dann hat der Browser weniger zu Rechnen als bei einem Top-Down approach. Unabhängig davon wie du es machst, häng den erstellten Baum erst dann in den "sichtbaren" Browserbaum ein wenn deine erstellung abgeschlossen ist - halt Dir den baum einfach so im Speicher rumliegen?
Irgendwo in diesem Forum liegt ein HTML render rum. Dieser interpretiert XML konformes HTML, erzeugt daraus DOM und fügt es einem bestehenden Browser DOM Baum hinzu. Habe lange mit dem konstrukt gearbeitet - die darstellung von 100 kByte HTML Code (welcher über diese Engine interpretiert und DOM hinzugefügt wird) dauerte damit vielleicht 100 - 200 ms -> nicht spürbarer delay. Vermute dass die Performance heutiger Browser (und speziell auch der Hardware) da noch einiges mehr ermöglicht.

Gruss

gepostet vor 16 Jahre, 1 Monat von Blabbo

ganz einfach, flash nehmen :)

Auf diese Diskussion antworten