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!
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 16 | CH 23 | CH 31 | FF 8 | FF 17 | FF 25 | IE 9 | IE 10 | IE 11 | Arány | Aktuális eredmény | Frissítés | Kód |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
if és elseif (== vizsgálattal): | 27 ms | 17 ms | 16 ms | 53 ms | 25 ms | 33 ms | 370 ms | 43 ms | 51 ms | % | ms | Frissít | Kó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 ms | 17 ms | 31 ms | 55 ms | 38 ms | 30 ms | 406 ms | 43 ms | 107 ms | % | ms | Frissít | Kó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 ms | 17 ms | 31 ms | 94 ms | 30 ms | 34 ms | 452 ms | 204 ms | 94 ms | % | ms | Frissít | Kó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 ms | 17 ms | 31 ms | 79 ms | 30 ms | 32 ms | 457 ms | 204 ms | 86 ms | % | ms | Frissít | Kó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 ms | 17 ms | 32 ms | 72 ms | 30 ms | 29 ms | 376 ms | 202 ms | 45 ms | % | ms | Frissít | Kó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 ms | 17 ms | 31 ms | 71 ms | 34 ms | 32 ms | 378 ms | 204 ms | 43 ms | % | ms | Frissít | Kó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 ms | 13 ms | 15 ms | 51 ms | 25 ms | 26 ms | 234 ms | 34 ms | 42 ms | % | ms | Frissít | Kó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 ms | 26 ms | 16 ms | 63 ms | 30 ms | 27 ms | 327 ms | 34 ms | 42 ms | % | ms | Frissít | Kó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.
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 16 | CH 23 | CH 31 | FF 8 | FF 17 | FF 25 | IE 9 | IE 10 | IE 11 | Arány | Aktuális eredmény | Frissítés | Kód |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
for() | 22 ms | 13 ms | 16 ms | 64 ms | 13 ms | 20 ms | 246 ms | 26 ms | 42 ms | % | µs | Frissít | Kód részlet |
var iteration = 10000000; for(var i = 0; i < iteration; $i++); | |||||||||||||
while() | 22 ms | 13 ms | 15 ms | 59 ms | 13 ms | 19 ms | 141 ms | 22 ms | 22 ms | % | µs | Frissít | Kód részlet |
var iteration = 10000000; var i = 0; while(i < iteration){ i++; } | |||||||||||||
for() visszafelé relációval | X ms | 13 ms | 16 ms | X ms | 13 ms | 20 ms | X ms | 25 ms | 39 ms | % | µs | Frissít | Kód részlet |
var iteration = 10000000; for(var i = iteration; i > 0; i--); | |||||||||||||
for() visszafelé true/false vizsgálattal | X ms | 18 ms | 16 ms | X ms | 13 ms | 26 ms | X ms | 30 ms | 19 ms | % | µs | Frissít | Kód részlet |
var iteration = 10000000; for(var i = iteration; i--; ); | |||||||||||||
while() visszafelé relációval | X ms | 13 ms | 16 ms | X ms | 13 ms | 20 ms | X ms | 21 ms | 33 ms | % | µs | Frissít | Kód részlet |
var iteration = 10000000; while(iteration > 0){ iteration--; } | |||||||||||||
while() visszafelé true/false vizsgálattal | X ms | 18 ms | 31 ms | X ms | 13 ms | 25 ms | X ms | 30 ms | 38 ms | % | µs | Frissít | Kó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.
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 16 | CH 23 | CH 31 | FF 8 | FF 17 | FF 25 | IE 9 | IE 10 | IE 11 | Arány | Aktuális eredmény | Frissítés | Kód |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Előre kiszámított - length: | 13 ms | 13 ms | 15 ms | 42 ms | 14 ms | 10 ms | 210 ms | 29 ms | 19 ms | % | µs | Frissít | Kó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 ms | 13 ms | 31 ms | 63 ms | 13 ms | 9 ms | 490 ms | 29 ms | 22 ms | % | µs | Frissít | Kó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.
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 16 | CH 23 | CH 31 | FF 8 | FF 17 | FF 25 | IE 9 | IE 10 | IE 11 | Arány | Aktuális eredmény | Frissítés | Kód |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Object() : for(var val in aHash); | 21 ms | 18 ms | 32 ms | 5 ms | 7 ms | 9 ms | 9 ms | 5 ms | 11 ms | % | µs | Frissít | Kó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 ms | 20 ms | 15 ms | 10 ms | 7 ms | 9 ms | 11 ms | 5 ms | 4 ms | % | µs | Frissít | Kó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 ms | 45 ms | 31 ms | 18 ms | 20 ms | 28 ms | 14 ms | 9 ms | 58 ms | % | µs | Frissít | Kó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 ms | 45 ms | 32 ms | 18 ms | 19 ms | 30 ms | 16 ms | 10 ms | 92 ms | % | µs | Frissít | Kó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
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 16 | CH 23 | CH 31 | FF 8 | FF 17 | FF 25 | IE 9 | IE 10 | IE 11 | Arány | Aktuális eredmény | Frissítés | Kód |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
feltöltés indexeléssel, aHash[i] = tmp; | 156 ms | 119 ms | 125 ms | 32 ms | 22 ms | 22 ms | 56 ms | 17 ms | 34 ms | % | µs | Frissít | Kó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 ms | 58 ms | 125 ms | 60 ms | 16 ms | 23 ms | 95 ms | 14 ms | 32 ms | % | µs | Frissít | Kó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 ms | 125 ms | 110 ms | 57 ms | 68 ms | 60 ms | 50 ms | 19 ms | 36 ms | % | µs | Frissít | Kó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
Iterációk száma: 10.000.000
Teszt | CH 16 | CH 23 | CH 31 | FF 8 | FF 17 | FF 25 | IE 9 | IE 10 | IE 11 | Arány | Aktuális eredmény | Frissítés | Kód |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
if (typeof obj.tmp != 'undefined'){;} | 68 ms | 47 ms | 63 ms | 971 ms | 43 ms | 43 ms | 1497 ms | 682 ms | 570 ms | % | µs | Frissít | Kód részlet |
var obj = { foo: 'bar'}; // test while(i < 10000000) { if (typeof obj.tmp != 'undefined'){;} i++; } | |||||||||||||
if (obj.tmp != undefined) {;} | 96 ms | 47 ms | 62 ms | 1140 ms | 226 ms | 39 ms | 1143 ms | 126 ms | 112 ms | % | µs | Frissít | Kód részlet |
var obj = { foo: 'bar'}; // test while(i < 10000000) { if (obj.tmp != undefined) {;} i++; } | |||||||||||||
if (obj.tmp !== undefined) {;} | 105 ms | 43 ms | 63 ms | 1065 ms | 50 ms | 36 ms | 1036 ms | 146 ms | 89 ms | % | µs | Frissít | Kód részlet |
var obj = { foo: 'bar'}; // test while(i < 10000000) { if (obj.tmp !== undefined) {;} i++; } | |||||||||||||
if (obj.hasOwnProperty('tmp')) {;} | 757 ms | 783 ms | 702 ms | 1121 ms | 682 ms | 418 ms | 1988 ms | 1120 ms | 659 ms | % | µs | Frissít | Kód részlet |
var obj = { foo: 'bar'}; // test while(i < 10000000) { if (obj.hasOwnProperty('tmp')) {;} i++; } | |||||||||||||
if ('tmp' in obj) {;} | 1132 ms | 1425 ms | 920 ms | 618 ms | 556 ms | 483 ms | 1787 ms | 1196 ms | 922 ms | % | µs | Frissít | Kód részlet |
var obj = { foo: 'bar'}; // test while(i < 10000000) { if ('tmp' in obj) {;} i++; } | |||||||||||||
if (obj.tmp) {;} | X ms | 48 ms | 63 ms | X ms | 107 ms | 31 ms | X ms | 80 ms | 33 ms | % | µs | Frissít | Kó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 :)...