nemoinho: Geschwindigkeit optimieren

Beitrag lesen

Moin Moin,

So ganz ist mir die Notwendigkeit noch nicht klar.
Warum muss #container durch einen Wrapper ersetzt werden, warum kannst du nicht #container wie gewünscht formatieren?

Weil ich via JS die Höhe des gesammten Inhalt ermitteln will, und es ist bedeutend schneller nur von einem element die offsetHeight abzufragen, als von jedem einzelnen, zumal auch noch margin's mit in die höhe einfliessen sollen.

Soll das Script in fremden Seiten arbeiten, wo du die Formatierung von #container nicht unter Kontrolle hast? Da könnten aber auch für dein Wrapper-Div Formatierungen gelten, die du nicht unter Kontrolle hast (schon allein über den Element-Selektor div). Da würde ich mich fragen, ob es nicht generell performanter wäre, wenn du alle CSS-Eigenschaften, auf die du dabei Wert legst, für #container selber explizit per JavaScript setzt ...?

1. Ja es soll auch auf Seiten laufen, auf die ich nicht direkt einfluss habe und
2. Das Design/Layout des Containers sowie des Inhalt sollen unabhängig vom Script sein, daher diese "Zwischenschicht".

so meine Frage ist nun genauer definiert, wie groß ist der Unterschied zwischen appendChild() und insertBefore() bezüglich der Geschwindigkeit

Das dürfte generell erst Mal kaum einen Unterschied machen. Beide hängen einen Knoten "irgendwo" in einen DOM-(Teil-)Baum ein, lediglich die Position ist eine andere.
Bei deiner derzeit gewählten Form,
wrapper.insertBefore(knoten, wrapper.firstChild)
muss allerdings auch wrapper.firstChild jedes Mal neu ermittelt werden - da könnte appendChild ein Quentchen schneller sein, weil du die Position da nicht im Script selber angeben musst, sondern den Interpreter sich selber drum kümmern lässt.

Das dachte ich mir bereits und stimmt die zusätzliche abfrage ist langsamer, allerdings ist diese Methode immernoch schneller als das Array umzudrehen und dann alles hinten anzufügen :)

und gibt es noch großen Optimierungsbedarf, ab der variable 'container' abwärts?

Hängt das wrapper-Element zu dem Zeitpunkt, wo du die Kindknoten einhängst, schon im Dokument? (Sieht nach deinem Beispielcode nicht so aus, aber ich frag trotzdem mal ...)
Es erst nach dem Einhängen aller Kindelemente ins Dokument einzufügen, sollte auf jeden Fall die schnellere Alternative sein.

Generell gilt: DOM-Manipulationen gehen idR. immer schneller, wenn sie "ausserhalb" des DOMs des aktuellen Dokumentes stattfinden.

#container auch erst aus dem Dokument herauszulösen (removeChild), bevor dessen Kindknoten "entnommen" werden, könnte ggf. noch etwas bringen. (Sofern vom Ablauf her möglich; kann ja auch danach wieder engefügt werden, wenn nötig.)

Ja daran hatte ich noch gar nicht gedacht, aber ich probier da mal ein bisschen rum, wahrscheinlich bringt das dann auch noch mal nen ganzes Stück

for(tmp = container.childsNodes, i = tmp.length; i--;)

wrapper.insertBefore(tmp[i], wrapper.firstChild);


> Auch wenn das "Verschieben" von DOM-Knoten die Hauptbremse sein dürfte, kann man hier evtl. noch ein bisschen optimieren.  
>   
> Dass in der Abbruchbedingung die Länge der childNodes immer wieder neu ermittelt werden muss, bremst auch ein bisschen. (Und wrapper.firstChild jedes Mal auf's neue bestimmen beim Einfügen eines Knotens auch, s.o.)  
>   
> Ich würde es ohne eigenen Zähler mit einer While-Schleife probieren, und appendChild statt insertBefore nutzen:  
> ~~~javascript

var fChild;  

> while(fChild = container.firstChild) {  
>   wrapper.appendChild(fChild);  
> }

So lange container noch ein firstChild hat, hänge dieses hinten an wrapper dran.
Die Hilfsvariable fChild deshalb, damit container.firstChild nicht beim Anhängen an wrapper noch ein zweites Mal ausgewertet werden muss - der Einsatz des .-Operators "kostet" relativ viel. Gerade im Bereich solcher Mirco-Optimierung kann sich auch das bemerkbar machen.

Von einer while-schleife sehe ich i.d.R. ab, da sie oft langsamer ist als eine for-schleife, allerdings ist dies ja bei JS nicht unbedingt der Fall, zumindest kein relevanter, aber das gewählte Konstrukt ist schon beabsichtigt, den dadurch wird nur einmal ermittelt, wie viele Kindknoten da sind und dann nur kontrolliert, ob die Schleifenbedingung noch wahr ist, weil in js alles wahr ist, was nicht false, 0, null oder undefined ist.
Wobei ich jetzt in der Vorschau grade erst sehe, dass bei deiner Variante ja eine komplette Abfrage wegfällt, sprich dürfte schneller sein, ich prob das mal aus, wenn ich das Script wieder offen habe, schreibe nämlich ganz aktuell an nem kleinen Hack, damit ich nicht jeden Tag alles möglich nachlesen muss, einstellen muss, weil das etwas umständlich wird bei der Bundeswehr...

Ach ja, P.S.: So, wie du das ganze hier aufbereitet hast, gehe ich davon aus, dass ein "Umhängen" der Kindknoten per

wrapper.innerHTML = container.innerHTML;

container.innerHTML = "";


> keine für dich ernsthaft in Betracht zu ziehende Alternative wäre?  
> Das könnte noch mal deutlich schneller sein, als "richtige" DOM-Manipulation;  
  
Nein, dass ist auch keine Möglichkeit, vor allem aufgrund besagter Problematik mit den Eventhandlern.  
  
Aber mir ist auch noch meine äußerst dämliche Kurzsichtigkeit aufgefallen, denn die create-funktion ist ja "rough and ready" und dabei mach ich eine ziemlich dumme Abfrage:  
~~~javascript
...  
if(typeof(attr[i]) == 'object')  
...

denn es ist ja eigentlich nur ein object möglich, das style-object, also sollte es aus Performancegründen eher so da stehen, weil die Geschwindigkeit der create-funktion ja in das script mit einfließt:

...  
if(i == 'style')  
...

Außerdem ist mir noch das cssText Attribute eingefallen, welches eigentlich in allen wichtigen Browsern, inkl. IE, funktioniert, damit könnte ich die Funktion nochmal deutlich beschleunigen, da nun nur noch einmal pro wrapper auf das DOM zugegriffen werden müsste

var wrapper = create('div',{'style':{  
  'cssText':'margin:0;padding:0;border:none;background:transparent;outline:none;width:auto;height:auto;'  
}});

mfG Felix Nehrke

P.S.: Besuche unseren Blog:  http://www.pommes-blog.de

--
Manchmal gibs was neues :)
fo:| ch:| rl:( br:> n4:? ie:( va:) de:> zu:) fl:( ss:| ls:[ js:)