ugrás a tartalomhoz

JS benchmark: sok elem beszúrása az oldalba

fchris82 · 2008. Aug. 25. (H), 19.20
Igazából nincs semmi kérdésem, csak gondoltam megosztom veletek, hogy mit csináltam :)

Kíváncsi voltam, hogy ha JS-ben szeretném legenerálni az oldal egy részét, akkor vajon milyen módszerrel érdemes. Az alábbi ötleteim támadtak:
1. createElement + appendChild
2. Létrehozom a stringet, pl "<div></div><div></div>...", és innerHTML-lel "adom" hozzá.
3. Rögtön az innerHTML-t bővítgetem

Továbbá felmerült az is, hogy vajon hogyan érdemes a stílus paramétereket megadni az új elemnek.
1. setAttribute('style', '[komplett stílus]'). Itt van egy olyan probléma, hogy IE alatt ez a megoldás nem működik. Lásd: http://www.quirksmode.org/dom/w3c_core.html és http://www.quirksmode.org/bugreports/archives/2005/03/setAttribute_does_not_work_in_IE_when_used_with_th.html . A probléma megoldását az utóbbiról vettem. (lásd forrás)
2. Egyesével végigmegyek és obj.style.[tulajdonság] = 'érték' megoldást használom.
3. "Stringes" esetben persze az előző kettő opció nem játszik.

A mérés WinXP Prof operációs rendszer alatt készült, a táblázatban az értékek ms-ok, és a kisebb érték a jobb. 10 000 div-et kellett beszúrniuk.

A tapasztalatok:
- A string + innerHTML megoldás annyira lassú minden böngészőben, hogy megkockáztatom a kijelentést: Soha ne használd arra, hogy "HTML elemekkel" így bővítsd az oldalt. A forrásból ki is hagytam ezt a tesztet, mert 1000 div esetén FF és IE is rendesen megizzad, a többin nem is próbáltam, már csak 100-zal.
- Amint a táblázatból kitűnik, minden böngészőben van különbség a két eljárás között, és általában a setAttribute() megoldás előnyére (még ha néha elég kicsi is)
IE6IE7FF3Opera 9.26Safari 3.1.2
setAttribute()106812714851700453
appendChild()23415633434494
style118813918581618523
appendChild()234156348279664

- Az eredmények 4-4 mérés átlagából származnak, kivéve Opera, ahol akkora volt a szórás, hogy inkább 5-öt mértem :D Operánál eléggé ingadozott, a többinél folyamatosan ugyanazok az értékek jöttek nagyjából.
- Érdekes, hogy Safarinál a "style" módon stílusozott elemeket sokkal lassabban adja hozzá az oldalhoz. Ez a jelenség akkor is tapasztalható volt, ha felcseréltem a tesztek futásának sorrendjét. (94 ms vs 664 ms)
- További érdekesség még, hogy FF3 alatt az ilyen elemeket sokkal lassabban hozza létre! (485 ms vs 858 ms)

Forrás:

<html>
<head>
  <title>JS Benchmark</title>
  <script>
  function test() {
    var n, matrix;
    n = 10000;
    matrix = [];
    t      = [];

    // Mátrix léterhozása
    t.push(new Date());
    for(i=0;i<n;i++) {
      matrix[i] = document.createElement('div');
      matrix[i].setAttribute('id', 'div'+i);
      if(document.all) {
        matrix[i].style.cssText = 'border: 1px solid black; width: 2px; height: 2px';
      } else {
        matrix[i].setAttribute('style', 'border: 1px solid black; width: 2px; height: 2px');
      }
    }
    t.push(new Date());

    // Megjelenítés
    c = document.getElementById('container');
    t.push(new Date());
    for(i=0;i<n;i++) {
      c.appendChild(matrix[i]);
    }
    t.push(new Date());

    // Tartalom törlése
    c.innerHTML = '';

    // Mátrix léterhozása
    t.push(new Date());
    for(i=0;i<n;i++) {
      matrix[i] = document.createElement('div');
      matrix[i].setAttribute('id', 'div'+i);
      matrix[i].style.border = '1px solid black';
      matrix[i].style.width  = '2px';
      matrix[i].style.height = '2px';
    }
    t.push(new Date());

    // Megjelenítés
    c = document.getElementById('container');
    t.push(new Date());
    for(i=0;i<n;i++) {
      c.appendChild(matrix[i]);
    }
    t.push(new Date());

    document.getElementById('value1').innerHTML = (t[1].getTime()-t[0].getTime()) + ' ms';
    document.getElementById('value2').innerHTML = (t[3].getTime()-t[2].getTime()) + ' ms';
    document.getElementById('value3').innerHTML = (t[5].getTime()-t[4].getTime()) + ' ms';
    document.getElementById('value4').innerHTML = (t[7].getTime()-t[6].getTime()) + ' ms';
  }

  window.onload = test;
  </script>
</head>
<body>
<h1>document.createElement() + setAttribute('style', '...')</h1>
  <div id="value1"></div>
<h1>container.appendChild()</h1>
  <div id="value2"></div>

<hr/>

<h1>document.createElement() + style.[...] = '...'</h1>
  <div id="value3"></div>
<h1>container.appendChild()</h1>
  <div id="value4"></div>

<h2>Container</h2>
  <div id="container"></div>
</body>
</html>
Ui:
A BBEditor a szövegszerkesztőből vagy böngészőből másolt tabokkal elválasztott cellás formázását tudja táblázattá alakítani automatikusan.

Ez nem működik :$ Vagy én csináltam vmit rosszul :?
 
1

A string + innerHTML megoldás annyira lassú minden böngésző

toxin · 2008. Aug. 26. (K), 07.19
valami benézést sejtek, csak nem tudom én vagy a te részedről :) , innerHTML töltésnek sokkal gyorsabbnak kéne lennie, mint a DOM konstrukciós műveletnek, nálam az arányok megfelelnek az itt mértekkel http://bdn.backbase.com/blog/grauw/javascript-html-construction-benchmark

mátrix feltöltése 10000 elemnél is < 100 ms, 1000 elemnél már elhanyaglható 0-20ms különböző böngészőkben, innerHTML töltési idő nagyjából 1/2 az appendChilld-hez képest, inline stílusbeállítást nem használtam, gyakorlatban is alábbi módon töltök

másrészt most ébredtem bővel lehet, hogy vmit benéztem :))
    <html>  
    <head>  
      <title>JS Benchmark</title>
	  <style type="text/css">
	  	
		.test{
			border: 1px solid black; width: 2px; 
			height: 2px;
		}
		
	  </style>  
      <script> 
      function test() {  
        var n, matrix;  
        n = 10000;  
        matrix = [];  
        t      = [];  
     
       // Mátrix léterhozása  
       t.push(new Date());  
       for(i=0;i<n;i++) {  
         matrix[i] = document.createElement('div');  
         matrix[i].setAttribute('id', 'div'+i);  
         if(document.all) {  
           matrix[i].style.cssText = 'border: 1px solid black; width: 2px; height: 2px';  
         } else {  
           matrix[i].setAttribute('style', 'border: 1px solid black; width: 2px; height: 2px');  
         }  
       }  
       t.push(new Date());  
     
       // Megjelenítés  
       c = document.getElementById('container');  
       t.push(new Date());  
       for(i=0;i<n;i++) {  
         c.appendChild(matrix[i]);  
       }  
       t.push(new Date());  
     
       // Tartalom törlése  
       c.innerHTML = '';  
     
       // Mátrix léterhozása  
       t.push(new Date());  
       for(i=0;i<n;i++) {  
         matrix[i] = document.createElement('div');  
         matrix[i].setAttribute('id', 'div'+i);  
         matrix[i].style.border = '1px solid black';  
         matrix[i].style.width  = '2px';  
         matrix[i].style.height = '2px';  
       }  
       t.push(new Date());  
     
       // Megjelenítés  
       c = document.getElementById('container');  
       t.push(new Date());  
       for(i=0;i<n;i++) {  
         c.appendChild(matrix[i]);  
       }  
       t.push(new Date()); 
	   
	          // Tartalom törlése  
       c.innerHTML = '';  
     
       // Mátrix léterhozása  
       t.push(new Date());  
       for(i=0;i<n;i++) {  
         matrix[i] = '<div class="test"></div>';  
       }  
       t.push(new Date());  
     
       // Megjelenítés  
       c = document.getElementById('container');  
       t.push(new Date());  
       c.innerHTML = matrix.join("");  
       t.push(new Date());  
     
       document.getElementById('value1').innerHTML = (t[1].getTime()-t[0].getTime()) + ' ms';  
       document.getElementById('value2').innerHTML = (t[3].getTime()-t[2].getTime()) + ' ms';  
       document.getElementById('value3').innerHTML = (t[5].getTime()-t[4].getTime()) + ' ms';  
       document.getElementById('value4').innerHTML = (t[7].getTime()-t[6].getTime()) + ' ms';
	   document.getElementById('value5').innerHTML = (t[9].getTime()-t[8].getTime()) + ' ms';  
       document.getElementById('value6').innerHTML = (t[11].getTime()-t[10].getTime()) + ' ms';  
     }  
     
     window.onload = test; 
     </script>  
   </head>  
   <body>  
   <h1>document.createElement() + setAttribute('style', '...')</h1>  
     <div id="value1"></div>  
   <h1>container.appendChild()</h1>  
     <div id="value2"></div>  
     
   <hr/>  
     
   <h1>document.createElement() + style.[...] = '...'</h1>  
     <div id="value3"></div>  
   <h1>container.appendChild()</h1>  
     <div id="value4"></div>
	 
	  <hr/> 
	  
	 <h1>string + style</h1>  
     <div id="value5"></div>  
   <h1>container innerHTML</h1>  
     <div id="value6"></div>   
     
   <h2>Container</h2>  
     <div id="container"></div>  
   </body>  
   </html>  
érdekes lehet még a stringek összefűzése különböző módszerekkel,
Conclusions

Though this analysis, a number of things about string performance have been observed:

* Native string operations in all browsers have been optimized to the point where borrowing techniques from other languages (such as passing around a single buffer for use by many methods) is for the most part unneeded.
* Array.join still seems to be the fastest method with Internet Explorer; either += or String.prototype.concat.apply(”", arguments) work best for all other browsers.
* Firefox has definite issues with accessing argument members via dynamic/variables
* And of course, the reminder to not ignore the data
http://www.sitepen.com/blog/2008/05/09/string-performance-an-analysis/

fent én is az Array.join-t használtam

üdv Csaba
2

Wow

fchris82 · 2008. Aug. 26. (K), 15.25
Valóban. Vmit írtózatosan elkavarhattam :D Ma is tanultam vmit :) Ugyanakkor a scriptedben volt egy kis csalás:
- nem adtál id attributumot a diveknek
- class-t használtál nem pedig style-t, ami szintén gyorsított
FF3 alatt hozzáadva ezt a két dolgot (5, 249)-ről (18, 541)-re változott az eredmény! De még így is gyorsabb volt úgy 40%-al.

Tudom, hogy a class gyorsabb egyébként, de nem életszerű, hogy üres diveket akar az ember beszúrkálni, ugyanolyan tulajdonsággal. Legalábbis nálam nem ez a helyzet :)

Egyébként a "javascript benchmark dom"-ra rákeresve jó sok ilyen cuccot találtam, de ez a szóhármas csak ma jutott eszembe... Itt van egy rossz példa az innerHTML használatra: http://andrew.hedges.name/experiments/innerhtml/ . Nekem nagyságrendekkel több jött ki innerHTML-re. Most így elsőre nem is látom, hogy miért :-/ Nah, mindegy :)
3

http://www.liligo.hu/

toxin · 2008. Aug. 26. (K), 18.01
indíts el egy keresést , és középen a találati elemek vannak így kirakva, bár a generálás ott velocity2js-el történik, ami már átvezett js template motorok világába http://weblabor.hu/blog/20061119/kliensoldalisablon#comment-36747 lehet frissíteni kéne :)

üdv Csaba

jav: márha vannak találatok, szóval a http://www.liligo.fr -en