cross browser - Skillnader mellan switch och if-else i JavaScript


Grabbar, jag har ett par frågor:

  1. Finns det en prestandaskillnad i JavaScript mellan en switch-sats och en if...else?
  2. Om så, varför?
  3. Är beteendet hos switch och if...else olika i olika webbläsare? (Firefox, IE, Chrome, Opera, Safari)

Anledningen till att jag ställer denna fråga är att det verkar som att jag får bättre prestanda på ett switch-uttryck med ungefär 1000 fall i Firefox.

Redigerad Tyvärr är detta inte min kod, Javascript genereras på serversidan från ett kompilerat bibliotek och jag har ingen åtkomst till koden. Metoden som genererar javascript kallas

CreateConditionals(string name, string arrayofvalues, string arrayofActions)

notera arrayofvalues är en kommaseparerad lista.

vad det producerar är

function [name] (value) {
  if (value == [value from array index x]) {
     [action from array index x]
  }
}

Obs: där [name]=namnet som skickas in i serversida-funktionen

Nu ändrade jag utdata från funktionen för att kunna infogas i ett TextArea, skrev lite JavaScript-kod för att analysera funktionen och konverterade den till en uppsättning case-satser.

slutligen kör jag funktionen och den fungerar bra men prestandan skiljer sig åt i IE och Firefox.

Svar #1

Svara i allmänna drag:

  1. Ja, vanligtvis.
  2. Se mer information här
  3. Ja, eftersom varje har en annan JS-processmotor, men när jag körde ett test på webbplatsen nedan, presterade switch alltid bättre än if, elseif vid ett stort antal iterationer.

Testsida

Svar #2

Ibland är det bättre att inte använda någon av dem. Till exempel, i en "dispatch"-situation, låter Javascript dig göra saker på ett helt annat sätt:

function dispatch(funCode) {
  var map = {
    'explode': function() {
      prepExplosive();
      if (flammable()) issueWarning();
      doExplode();
    },

    'hibernate': function() {
      if (status() == 'sleeping') return;
      // ... I can't keep making this stuff up
    },
    // ...
  };

  var thisFun = map[funCode];
  if (thisFun) thisFun();
}

Att ställa in flervägsgrenning genom att skapa ett objekt har många fördelar. Du kan lägga till och ta bort funktionalitet dynamiskt. Du kan skapa dispatch-tabellen från data. Du kan undersöka den programmeringsmässigt. Du kan bygga hanterarna med andra funktioner.

Det tillkommer en extra kostnad för ett funktionsanrop för att nå motsvarigheten till ett "case", men fördelen (när det finns många case) är en hash-uppslagning för att hitta funktionen för en viss nyckel.

Svar #3

Prestandaskillnaden mellan en switch och if...else if...else är liten, de gör i princip samma arbete. En skillnad mellan dem som kan spela roll är att uttrycket som ska testas endast utvärderas en gång i en switch, medan det utvärderas för varje if. Om det är kostsamt att utvärdera uttrycket är det förstås snabbare att göra det en gång än att göra det hundra gånger.

Skillnaden i implementationen av dessa kommandon (och alla skript i allmänhet) skiljer sig ganska mycket mellan webbläsare. Det är vanligt att se ganska stora prestandaskillnader för samma kod i olika webbläsare.

Eftersom du knappast kan prestandatesta all kod i alla webbläsare, bör du välja den kod som passar bäst för det du gör och försöka minska mängden arbete som utförs snarare än att optimera hur det görs.

Svar #4

Pointys svar föreslår användningen av ett objektliteral som ett alternativ till switch eller if/else. Jag gillar också detta tillvägagångssätt, men koden i svaret skapar ett nytt map-objekt varje gång dispatch-funktionen anropas:

function dispatch(funCode) {
  var map = {
    'explode': function() {
      prepExplosive();
      if (flammable()) issueWarning();
      doExplode();
    },

    'hibernate': function() {
      if (status() == 'sleeping') return;
      // ... I can't keep making this stuff up
    },
    // ...
  };

  var thisFun = map[funCode];
  if (thisFun) thisFun();
}

Om map innehåller ett stort antal poster kan detta skapa betydande overhead. Det är bättre att skapa actionkartan endast en gång och sedan använda den redan skapade kartan varje gång, till exempel:

var actions = {
    'explode': function() {
        prepExplosive();
        if( flammable() ) issueWarning();
        doExplode();
    },

    'hibernate': function() {
        if( status() == 'sleeping' ) return;
        // ... I can't keep making this stuff up
    },
    // ...
};

function dispatch( name ) {
    var action = actions[name];
    if( action ) action();
}

Relaterade artiklar