Kiedy spojrzałem na rozwiązania w innych odpowiedziach, zobaczyłem pewne rzeczy, które, jak wiem, są złe dla wydajności. Zamierzałem zamieścić je w komentarzu, ale pomyślałem, że lepiej będzie go porównać i podzielić się wynikami. Możesz to przetestować sam . Poniżej znajdują się moje wyniki (ymmv) znormalizowane po najszybszej operacji w każdej przeglądarce (pomnóż czas 1,0 przez znormalizowaną wartość, aby uzyskać czas bezwzględny w ms).
Chrome Firefox Opera MSIE Safari Node
-------------------------------------------------- -----------------
1.0 czas 37ms 73ms 68ms 184ms 73ms 21ms
if-natychmiastowe 1,0 1,0 1,0 2,6 1,0 1,0
jeśli-pośredni 1,2 1,8 3,3 3,8 2,6 1,0
natychmiastowe przełączenie 2,0 1,1 2,0 1,0 2,8 1,3
zakres przełączania 38,1 10,6 2,6 7,3 20,9 10,4
zakres przełączania 2 31,9 8,3 2,0 4,5 9,5 6,9
tablica przełączająca-pośrednia 35,2 9,6 4,2 5,5 10,7 8,6
przełącznik liniowo-liniowy 3,6 4,1 4,5 10,0 4,7 2,7
binarny przełącznik tablicowy 7,8 6,7 9,5 16,0 15,0 4,9
Testuj w systemie Windows 7 32bit z następującymi wersjami: Chrome 21.0.1180.89m , Firefox 15.0 , Opera 12.02 , MSIE 9.0.8112 , Safari 5.1.7 . Węzeł został uruchomiony na 64-bitowym systemie Linux, ponieważ rozdzielczość czasomierza w Node.js dla Windows wynosiła 10 ms zamiast 1 ms.
jeśli-natychmiast
Jest to najszybszy we wszystkich testowanych środowiskach, z wyjątkiem ... drumroll MSIE! (niespodzianka niespodzianka). Jest to zalecany sposób na jego wdrożenie.
if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else
jeśli-pośredni
Jest to wariant switch-indirect-array
z if
opcją -statements i działa znacznie szybciej niż switch-indirect-array
w prawie wszystkich testowanych środowiskach.
values=[
1000, 2000, ... 30000
];
if (val < values[0]) { /* do something */ } else
if (val < values[1]) { /* do something */ } else
...
if (val < values[29]) { /* do something */ } else
natychmiastowa zmiana
Jest to dość szybkie we wszystkich testowanych środowiskach i faktycznie najszybsze w MSIE. Działa, gdy można wykonać obliczenia w celu uzyskania indeksu.
switch (Math.floor(val/1000)) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
zakres przełączania
Jest to około 6 do 40 razy wolniejsze niż najszybsze we wszystkich testowanych środowiskach, z wyjątkiem Opery, gdzie zajmuje to około półtora raza dłużej. Jest powolny, ponieważ silnik musi porównać wartość dwukrotnie dla każdego przypadku. Zaskakujące jest to, że Chrome zajmuje prawie 40 razy dłużej, niż w przypadku najszybszej operacji w Chrome, podczas gdy MSIE zajmuje tylko 6 razy dłużej. Ale rzeczywista różnica czasu wynosiła tylko 74 ms na korzyść MSIE przy 1337 ms (!).
switch (true) {
case (0 <= val && val < 1000): /* do something */ break;
case (1000 <= val && val < 2000): /* do something */ break;
...
case (29000 <= val && val < 30000): /* do something */ break;
}
zakres przełączania 2
Jest to wariant, switch-range
ale z jednym porównaniem na skrzynkę, a zatem szybszy, ale wciąż bardzo wolny, z wyjątkiem Opery. Kolejność instrukcji case jest ważna, ponieważ silnik przetestuje każdą sprawę w kolejności kodu źródłowego ECMAScript262: 5 12.11
switch (true) {
case (val < 1000): /* do something */ break;
case (val < 2000): /* do something */ break;
...
case (val < 30000): /* do something */ break;
}
tablica przełączania pośredniego
W tym wariancie zakresy są przechowywane w tablicy. Jest to powolne we wszystkich testowanych środowiskach i bardzo wolno w Chrome.
values=[1000, 2000 ... 29000, 30000];
switch(true) {
case (val < values[0]): /* do something */ break;
case (val < values[1]): /* do something */ break;
...
case (val < values[29]): /* do something */ break;
}
tablicowo-liniowe wyszukiwanie
Jest to kombinacja liniowego wyszukiwania wartości w tablicy i instrukcji switch ze stałymi wartościami. Powodem, dla którego warto to wykorzystać, jest fakt, że wartości nie są znane do czasu uruchomienia. Jest wolny w każdym testowanym środowisku i zajmuje prawie 10 razy więcej czasu w MSIE.
values=[1000, 2000 ... 29000, 30000];
for (sidx=0, slen=values.length; sidx < slen; ++sidx) {
if (val < values[sidx]) break;
}
switch (sidx) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
switch-binary-switch
Jest to wariant array-linear-switch
z wyszukiwaniem binarnym. Niestety jest wolniejszy niż wyszukiwanie liniowe. Nie wiem, czy to moja implementacja, czy też wyszukiwanie liniowe jest bardziej zoptymalizowane. Możliwe też, że przestrzeń na klucze jest za mała.
values=[0, 1000, 2000 ... 29000, 30000];
while(range) {
range = Math.floor( (smax - smin) / 2 );
sidx = smin + range;
if ( val < values[sidx] ) { smax = sidx; } else { smin = sidx; }
}
switch (sidx) {
case 0: /* do something */ break;
...
case 29: /* do something */ break;
}
Wniosek
Jeśli wydajność jest ważna, użyj if
-statements lub switch
z natychmiastowymi wartościami.