JS Sebességteszt

php js c#

A JavaScript nyelv egy kliens oldali nyelv, nagyon sokmindent vele végeztetünk, többek között olyan okokból is, hogy felesleges számításokkal ne terheljük a szervert.
Azért is különösen érdemes odafigyelni a gyors kód megírására, mert a böngészőkben futó JS kód sebességét a böngésző, a futtató számítógépe nagyban befolyásolja.

Tekintsük át, hogyan tudjuk JS kódjainkat gyorsabbá tenni esetleges nagyobb, több (száz)ezres ciklusnál.

 
 
 

Figyelem! Az oldalon mutatott, mért sebességek a JS kódot futtató kliens (géptől) függően eltérhetnek, csak tájékoztató értékűek! Azonban az átlagosan elért eredmények átlaga jól mutatja, hogy melyik kóddal milyen eredményeket lehet elérni megfelelően magas iteráció szám felett!

A JS teszteknél az arány és aktuális eredmény oszlopok nem lesznek előre kitöltve, mert azok eltérő gépeken és böngészőkön teljesen más eredményt mutathatnak, így megtévesztő lenne az előre kitöltés!

Vezérlési szerkezetek (if, else, switch kombinációk):

Az elágazások a programozás során elengedhetetlen kellékek, ezért rögtön velük kezdjük

Iterációk száma: 10.000.000

Teszt CH 16CH 23CH 31 FF 8FF 17FF 25 IE 9IE 10IE 11 ArányAktuális eredményFrissítésKód
if és elseif (== vizsgálattal): 27 ms17 ms16 ms 53 ms25 ms33 ms 370 ms43 ms51 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    while(i < iteration){
        if(answer == 1) {}
            else if(answer == 2) {}
        i++;
    }
if, elseif és else (== vizsgálattal): 28 ms17 ms31 ms 55 ms38 ms30 ms 406 ms43 ms107 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    while(i < iteration){
        if(answer == 1) {}
            else if(answer == 3) {}
            else {}
       i++;
    }
if, elseif (=== vizsgálattal): 28 ms17 ms31 ms 94 ms30 ms34 ms 452 ms204 ms94 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    while(i < iteration){
        if(answer === 1) {}
            else if(answer === 2) {}
        i++;
    }
if, elseif és else (=== vizsgálattal): 29 ms17 ms31 ms 79 ms30 ms32 ms 457 ms204 ms86 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    while(i < iteration){
        if(answer === 1) {}
            else if(answer === 3) {}
            else {}
       i++;
    }
switch - case: 27 ms17 ms32 ms 72 ms30 ms29 ms 376 ms202 ms45 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    while(i < iteration){
        switch(answer) {
            case 1:
                break;
            case 2:
                break;
        }
        i++;
    }
switch - case - default: 29 ms17 ms31 ms 71 ms34 ms32 ms 378 ms204 ms43 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    while(i < iteration){
        switch(answer) {
            case 1:
                break;
            case 3:
                break;
            default:
                break;
        }
        i++;
    }
két ágú if-else teszt: 22 ms13 ms15 ms 51 ms25 ms26 ms 234 ms34 ms42 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    var x = 0;
    while(i < iteration){
        if(answer == 1) {
            x = 1;
        } else {
            x = 2;
        }
        i++;
    }
két ágú egysoros if, var = ()?:; 40 ms26 ms16 ms 63 ms30 ms27 ms 327 ms34 ms42 ms % msFrissítKód részlet
    var answer = 2;
    var iteration = 10000000;
    var i = 0;
    var x = 0;
    while(i < iteration){
        x = (answer==1)?1:2;
        i++;
    }

Konklúzió:

A vezérlési szerkezeteknél kitűnt az egysoros if lassúsága a normál if-else szerkezettel szemben.

A === típus egyezést is figyelembe vevő vizsgálatok általában lassabbnak bizonyultak a sima == érték vizsgálatnál, érdekes ez a PHP-nál pont fordítva volt.

A switch-nél a default ág jelenléte vagy hiánya nem okozott eltérést.

Böngészők tekintetében a Chrome vitte a mezőnyt mindenben, a Firefox nem sokkal lemaradva, és végül egy érdekesen lassú Internet Explorer 9. Meg kell említeni azonban, hogy az IE9 érdekesen működik, mert ha kellően sokszor egymás után lefuttatunk egy adott tesztet, akkor kimagaslóan jó (8-9ms) körüli eredményt produkál. Ezt valószínűsítem cacheléssel oldja meg, viszont azt az eredményt nem vehetjük alapul a többi böngészővel szemben, akik nem cacheből veszik az eredményt.

Frissítés (2013-01-04):

Elmondható, hogy minden böngésző 2x gyorsabban végrehajtja a teszteket, az IE10 még látványosabban fejlődött, bár picit mindig lemarad még így is.

Frissítés (2013-12-04):

Az IE11 úgy összességében jobb eredményeket produkál mint elődei. A Chrome és FF hozták a szokásos formát.

Normál számláló ciklusok tesztje (Counting-Loop):

A sima for() és while() ciklusokat hasonlítja egymáshoz, terhelés nélkül.

Iterációk száma: 10.000.000

Teszt CH 16CH 23CH 31 FF 8FF 17FF 25 IE 9IE 10IE 11 ArányAktuális eredményFrissítésKód
for() 22 ms13 ms16 ms 64 ms13 ms20 ms 246 ms26 ms42 ms % µsFrissítKód részlet
    var iteration = 10000000;
    for(var i = 0; i < iteration; $i++);
while() 22 ms13 ms15 ms 59 ms13 ms19 ms 141 ms22 ms22 ms % µsFrissítKód részlet
    var iteration = 10000000;
    var i = 0;
    while(i < iteration){
        i++;
    }
for() visszafelé relációval X ms13 ms16 ms X ms13 ms20 ms X ms25 ms39 ms % µsFrissítKód részlet
    var iteration = 10000000;
    for(var i = iteration; i > 0; i--);
for() visszafelé true/false vizsgálattal X ms18 ms16 ms X ms13 ms26 ms X ms30 ms19 ms % µsFrissítKód részlet
    var iteration = 10000000;
    for(var i = iteration; i--; );
while() visszafelé relációval X ms13 ms16 ms X ms13 ms20 ms X ms21 ms33 ms % µsFrissítKód részlet
    var iteration = 10000000;
    while(iteration > 0){
        iteration--;
    }
while() visszafelé true/false vizsgálattal X ms18 ms31 ms X ms13 ms25 ms X ms30 ms38 ms % µsFrissítKód részlet
    var iteration = 10000000;
	while(iteration--);

Konklúzió:

A while() ciklus futott gyorsabban, kivéve Chrome-ban, ott megegyezett a for() és while() ideje.

Az IE9 a harmadik frissítés után azonnal dobta cacheből az eredményt, a szokásos 10ms-is idő körül...

Frissítés (2013-01-04):

Mind a három böngésző javított az eredményein, az IE is sokat fejlődött, de picit le van még maradva itt.

Frissítés (2013-01-23):

Egy érdekes és szerintem hasznos teszt típussal bővítettem a for/while ciklusokat. Mégpedig a vissza felé számlálás, itt két megoldás van a ciklusok feltételénél, vagy "i > 0" (amíg nagyobb mint 0), vagy simán "i" a feltétel (amíg true). Nos ez úgy látszik (FireFox-t kivéve) egyáltalán nem mindegy, ugyan is az látszik, hogy a relációs kondíció gyorsabbnak bizonyult mind a for, mind a while esetében.

Frissítés (2013-12-04):

Szinte mindegyik új verziónál picit mintha esett volna a teljesítmény.

Folytonos ciklusok (For-Loop):

Ha előre tudjuk egy ciklus iterációinak számát, sokat gyorsíthatunk a dolgon ha azt fixre állítjuk

Iterációk száma: 10.000.000

Teszt CH 16CH 23CH 31 FF 8FF 17FF 25 IE 9IE 10IE 11 ArányAktuális eredményFrissítésKód
Előre kiszámított - length: 13 ms13 ms15 ms 42 ms14 ms10 ms 210 ms29 ms19 ms % µsFrissítKód részlet
    // init
    var i = 0; var tmp = '';
    while(i < 1000) {
      tmp += 'a';
      i++;
    }
    var x = Array();
    var i = 0;
    while(i < 10000000) {
      x.push(tmp);
      i++;
    }
    // test
    var size = x.length;
    for (var i=0; i < size; i++);
Előre kiszámítás nélküli - length: 37 ms13 ms31 ms 63 ms13 ms9 ms 490 ms29 ms22 ms % µsFrissítKód részlet
    // init
    var i = 0; var tmp = '';
    while(i < 1000) {
      tmp += 'a';
      i++;
    }
    var x = Array();
    var i = 0;
    while(i < 10000000) {
      x.push(tmp);
      i++;
    }
    // test
    for (var i=0; i < x.length; i++);

Konklúzió:

Már csak ha jól belegondolunk is, a várható eredményt hozzák a böngészők (motorok), így az előre kiszámított ciklus számmal jóval gyorsabb futást tudunk elérni.

Frissítés (2013-01-04):

Mind a három böngésző javított az eredményein, az IE is sokat fejlődött, de itt is le van még maradva picit.

Array() vagy Object() hash tömböknek?:

Keressük meg melyik megoldás a leghatékonyabb egy hash tömböt végig pörgetni, illetve módosítani.

A teszthez egy 50.000 elemű tömböt használtunk, bejegyzései 24byte-os kulcsot és 10k-nyi adatot tartalmaznak.

Teszt CH 16CH 23CH 31 FF 8FF 17FF 25 IE 9IE 10IE 11 ArányAktuális eredményFrissítésKód
Object() : for(var val in aHash); 21 ms18 ms32 ms 5 ms7 ms9 ms 9 ms5 ms11 ms % µsFrissítKód részlet
    // init
    var i = 0;
    var tmp = '';
    while(i < 10000) {
      tmp += 'a';
      i++;
    }
    var aHash = new Object();
    var i = 10000;
    while(i < 60000) {
        var addr = '100000000000000000000' + i.toString();
        aHash[''+ addr +''] = tmp;
        i++;
    }
    // test
    for(var val in aHash) ;
Array() : for(var val in aHash); 22 ms20 ms15 ms 10 ms7 ms9 ms 11 ms5 ms4 ms % µsFrissítKód részlet
    // init
    var i = 0;
    var tmp = '';
    while(i < 10000) {
      tmp += 'a';
      i++;
    }
    var aHash = new Array();
    var i = 10000;
    while(i < 60000) {
        var addr = '100000000000000000000' + i.toString();
        aHash[''+ addr +''] = tmp;
        i++;
    }
    // test
    for(var val in aHash) ;
Object() : for(var val in aHash) aHash[val] += 'a'; 46 ms45 ms31 ms 18 ms20 ms28 ms 14 ms9 ms58 ms % µsFrissítKód részlet
    // init
    var i = 0;
    var tmp = '';
    while(i < 10000) {
      tmp += 'a';
      i++;
    }
    var aHash = new Object();
    var i = 10000;
    while(i < 60000) {
        var addr = '100000000000000000000' + i.toString();
        aHash[''+ addr +''] = tmp;
        i++;
    }
    // test
    for(var val in aHash) aHash[val] += 'a';
Array() : for(var val in aHash) aHash[val] += 'a'; 48 ms45 ms32 ms 18 ms19 ms30 ms 16 ms10 ms92 ms % µsFrissítKód részlet
    // init
    var i = 0;
    var tmp = '';
    while(i < 10000) {
      tmp += 'a';
      i++;
    }
    var aHash = new Array();
    var i = 10000;
    while(i < 60000) {
        var addr = '100000000000000000000' + i.toString();
        aHash[''+ addr +''] = tmp;
        i++;
    }
    // test
    for(var val in aHash) aHash[val] += 'a';

Konklúzió:

Nagyjából mindegy, hogy Object() vagy Array()-t használunk, az Object() egy hajszálnyival jobban teljesített. Az IE9 meglepően jó eredményeket produkált... cache nélkül...

Frissítés (2013-01-04):

Chrome: nincs jelentős változás, tartja, talán hajszállal jobb

FireFox: hasonló a Chromehoz, valamicskét javult, de nem jelentős

IE: szépen javított az eddig is jó eredményein

Tömbök feltöltése:

Vizsgáljuk meg, hogyan járunk jobban ha egy nagy elemszámú tömböt akarunk feltölteni.

A teszthez 1.000.000 eleműre töltjük a tömböt, bejegyzünk 1k-nyi adatokat.

Teszt CH 16CH 23CH 31 FF 8FF 17FF 25 IE 9IE 10IE 11 ArányAktuális eredményFrissítésKód
feltöltés indexeléssel, aHash[i] = tmp; 156 ms119 ms125 ms 32 ms22 ms22 ms 56 ms17 ms34 ms % µsFrissítKód részlet
    // init
    var i = 0;
    var tmp = '';
    while(i < 1000) {
      tmp += 'a';
      i++;
    }
    var aHash = new Array();
    // teszt
    var i = 0;
    while(i < 1000000) {
        aHash[i] = tmp;
        i++;
    }
feltöltés push-sal, aHash.push(tmp); 67 ms58 ms125 ms 60 ms16 ms23 ms 95 ms14 ms32 ms % µsFrissítKód részlet
    // init
    var i = 0;
    var tmp = '';
    while(i < 1000) {
      tmp += 'a';
      i++;
    }
    var aHash = new Array();
    //teszt
    var i = 0;
    while(i < 1000000) {
        aHash.push(tmp);
        i++;
    }
feltöltés push-sal, aHash.push(tmp, tmp, tmp, tmp); 64 ms125 ms110 ms 57 ms68 ms60 ms 50 ms19 ms36 ms % µsFrissítKód részlet
    // init
    var i = 0;
    var tmp = '';
    while(i < 1000) {
      tmp += 'a';
      i++;
    }
    var aHash = new Array();
    //teszt
    var i = 0;
    while(i < 250000) {
        aHash.push(tmp, tmp, tmp, tmp);
        i++;
    }

Konklúzió:

A Chrome-t kivéve a feltöltést az indexeléssel a leggyorsabb csinálni, ha viszont függetlenek akarunk maradni, akkor a push() nyerő.

A push('aa') és push('aa','aa'...'aa') között nagy különbség nincs igazából (kivéve az IE-t).

Legjobb eredményeket a FireFox produkálta, majd az IE9 és Chrome következett, úgy látszik az IE9 tömbkezelésben egész jó.

Frissítés (2013-01-04):

Chrome: valamelyest javultak az értékek, bár több argumentú push-nál lassulás látható

FireFox: mint a Chrome-nál csak itt kiemelkedő a javulás

IE: igazi meglepetés, nagyon korrekt eredményeket produkált mind a 3 tesztben

Hogyan vizsgáljuk meg, hogy egy objektum eleme létezik-e?:

Iterációk száma: 10.000.000

Teszt CH 16CH 23CH 31 FF 8FF 17FF 25 IE 9IE 10IE 11 ArányAktuális eredményFrissítésKód
if (typeof obj.tmp != 'undefined'){;} 68 ms47 ms63 ms 971 ms43 ms43 ms 1497 ms682 ms570 ms % µsFrissítKód részlet
    var obj = { foo: 'bar'};
    // test
    while(i < 10000000) {
        if (typeof obj.tmp != 'undefined'){;}
        i++;
    }
if (obj.tmp != undefined) {;} 96 ms47 ms62 ms 1140 ms226 ms39 ms 1143 ms126 ms112 ms % µsFrissítKód részlet
    var obj = { foo: 'bar'};
    // test
    while(i < 10000000) {
        if (obj.tmp != undefined) {;}
        i++;
    }
if (obj.tmp !== undefined) {;} 105 ms43 ms63 ms 1065 ms50 ms36 ms 1036 ms146 ms89 ms % µsFrissítKód részlet
    var obj = { foo: 'bar'};
    // test
    while(i < 10000000) {
        if (obj.tmp !== undefined) {;}
        i++;
    }
if (obj.hasOwnProperty('tmp')) {;} 757 ms783 ms702 ms 1121 ms682 ms418 ms 1988 ms1120 ms659 ms % µsFrissítKód részlet
    var obj = { foo: 'bar'};
    // test
    while(i < 10000000) {
        if (obj.hasOwnProperty('tmp')) {;}
        i++;
    }
if ('tmp' in obj) {;} 1132 ms1425 ms920 ms 618 ms556 ms483 ms 1787 ms1196 ms922 ms % µsFrissítKód részlet
    var obj = { foo: 'bar'};
    // test
    while(i < 10000000) {
        if ('tmp' in obj) {;}
        i++;
    }
if (obj.tmp) {;} X ms48 ms63 ms X ms107 ms31 ms X ms80 ms33 ms % µsFrissítKód részlet
    var obj = { foo: 'bar'};
    // test
    while(i < 10000000) {
        // Figyelem, 0 vagy üres string esetén is false a vizsgálat
        // de sok esetben használható feltétel ez is
        if (obj.tmp) {;} 
        i++;
    }

Konklúzió:

Na itt aztán vegyes a kép... Böngészőnként eltérő melyik, melyiket részesíti előnyben. Ami jól látható, hogy Chrome-ban a typeof a legjobb és a !=, !== undefined szorosan követi.

FireFoxnál a ('tmp' in obj) adja a legjobb eredményt (pont a Chrome fordítottja), valamint az IE9 mindenhol sok időt kér, talán a !=, !== undefined vizsgálatok a legszerencsésebb választások.

Ha kódjainkban nem teszünk különbséget a futtató környezetben, akkor a !=, !== undefined vizsgálatok a javasoltak...:(

Frissítés (2013-01-04):

Felvetődött időközben (Perlaki Attila kérdésére), hogy az if(obj.tmp) egyszerű vizsgálat ki lett hagyva a tesztből. Igen valóban, mert ha a vizsgált változó létezik de 0 vagy üres string, akkor is false-t fog eredményül adni a vizsgálat.

A feltételt azonban bevettem a tesztbe, és egyúttal ezt a teszt kört az új böngésző trión is lefuttattam. Azért van kis meglepetés:

A Chrome sok esetben még gyorsabb lett, bár van ahol meg pont lassabb. A FireFox nagyon sokat, látványosan gyorsult és az IE10 is kezd felzárkózni, de még van mit behoznia.

Frissítés (2013-12-04):

A Firefox 25 szépen beállított az új rekordokat, ezt kellene a többieknek is követnie :)...

Az oldal PHP-s része a www.phpbench.com alapján készült, az ott felsorolt méréseket vette alapul, de attól eltérhetnek!
Az oldalt készítette Szentgyörgyi János @ dynamicart.hu | 2011-2013.
Creative Commons Licenc