Переключатель Javascript против если ... еще, если ... еще

143

Ребята, у меня есть пара вопросов:

  1. Есть ли разница в производительности между JavaScript switchи оператором if...else?
  2. Если так, то почему?
  3. Является ли поведение switchи if...elseотличается в разных браузерах? (FireFox, IE, Chrome, Opera, Safari)

Причина, по которой я задаю этот вопрос, заключается в том, что мне кажется, что я получаю более высокую производительность в switchзаявлении с примерно 1000-ю случаями в Firefox.


К сожалению, это не мой код, Javascript создается на стороне сервера из скомпилированной библиотеки, и у меня нет доступа к коду. Метод, который производит Javascript называется

CreateConditionals(string name, string arrayofvalues, string arrayofActions)

note arrayofvalues- список, разделенный запятыми.

что он производит

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

Примечание: где [name]= имя, переданное в функцию сервера

Теперь я изменил вывод функции для вставки в TextArea, написал некоторый код JavaScript для анализа функции и преобразовал его в набор caseоператоров.

наконец, я запускаю функцию, и она работает нормально, но производительность отличается в IE и Firefox.

Джон Хартсок
источник
1
Я хотел бы предложить пример кода, чтобы проверить, что является оптимальным. Я имею в виду, должна быть причина, по которой ты спрашиваешь об этом, верно?
Jcolebrand
Пожалуйста, опубликуйте, что вы делаете, потому что в моем долгом опыте было очень мало случаев, для которых я бы сказал, что заявление о переключении в 100 случаев или в серию из 100 частей, если / иначе было бы хорошей идеей.
Заостренный
извините, ребята, не сотни, а тысячи условий
Джон Хартсок
2
Всем спасибо за вклад. Но моя проблема не была на самом деле в разнице между if и swith. Это был код, работающий внутри оператора. +1 всем вам за вашу помощь. Извините за неудобства. Иногда вам просто нужно поговорить с другим человеком, чтобы найти решение.
Джон Хартсок

Ответы:

113

Отвечая в общих чертах:

  1. Да обычно.
  2. Подробнее здесь
  3. Да, поскольку у каждого свой механизм обработки JS, однако при выполнении теста на указанном ниже сайте коммутатор всегда выполнял операции if, elseif на большом количестве итераций.

Тестовый сайт

Томми
источник
1
Если вы хотите, чтобы TLDR о том, когда и какие условия использовать, является прямой ссылкой на сегмент статьи, в котором говорится
edhedges
2
@ Tommy Хорошая статья, спасибо, что поделились. Однако в статье говорится, что разница между производительностью switchи if/thenоператорами в JS ничтожна . В статье утверждается, что это происходит из-за неоднозначной switchоптимизации и различных способов работы различных движков JS. Цитата:Since most JavaScript engines don’t have such optimizations, performance of the switch statement is mixed.
Джаспер
3
Что-нибудь количественно показано в этом описании? Это звучит как гипотеза «лучшие практики / преждевременная оптимизация». Он также был написан 7 лет назад, поэтому оптимизация JavaScript сильно изменилась за это время. В скомпилированных языках разница в производительности между этими тремя операциями "почти никогда не бывает настолько значительной, чтобы о ней заботиться". Не пытайтесь оптимизировать вещи, которые не повлияют на реальную производительность. Оптимизировать читаемость.
Томсон Комер
3
@Tommy « Подробнее здесь » дает 404, что там было?
LogicDaemon
2
@LogicDaemon - IIRC - это ссылка на некое текстовое поле oRielly, в которое вошли некоторые подробные соображения / обсуждения производительности JS
Томми,
61

Иногда лучше не использовать ни того, ни другого. Например, в ситуации «отправки» Javascript позволяет вам делать вещи совершенно по-другому:

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();
}

Настройка многократного ветвления путем создания объекта имеет много преимуществ. Вы можете добавлять и удалять функции динамически. Вы можете создать таблицу отправки из данных. Вы можете проверить это программно. Вы можете создавать обработчики с другими функциями.

Есть дополнительные издержки вызова функции, чтобы получить эквивалент «case», но преимущество (когда есть много случаев) поиска хеша для поиска функции для определенного ключа.

Заостренный
источник
2
Ваша стратегия хороша, и я часто ее использую. Но, как указал @Michael Geary stackoverflow.com/a/45336805/5936119 , переменная карты должна быть объявлена ​​вне контекста диспетчеризации, в противном случае она всегда будет переоцениваться.
Даниэль Сантана
@DanielSantana правда, но я сомневаюсь, что это значительно дороже. В частности, после первоначального анализа функции сам код не нужно восстанавливать, поскольку текст является статическим.
Заостренный
18

Разница в производительности между a switchи if...else if...elseмала, в основном они выполняют одну и ту же работу. Одно из различий между ними, которое может иметь значение, состоит в том, что проверяемое выражение оценивается только один раз, и switchоно вычисляется для каждого if. Если оценивать выражение стоит дорого, то, конечно, делать это один раз быстрее, чем сто раз.

Разница в реализации этих команд (и всего сценария в целом) довольно сильно отличается в разных браузерах. Часто встречаются большие различия в производительности одного и того же кода в разных браузерах.

Поскольку вы вряд ли сможете протестировать производительность всего кода во всех браузерах, вам следует выбрать код, который лучше всего подходит для того, что вы делаете, и попытаться уменьшить объем выполненной работы, а не оптимизировать ее работу.

Guffa
источник
7
  1. Если есть разница, она никогда не будет достаточно большой, чтобы ее заметить.
  2. N / A
  3. Нет, все они работают одинаково.

В основном, используйте то, что делает код наиболее читабельным. Определенно есть места, где та или иная конструкция делает ее более чистой, удобочитаемой и удобной в обслуживании. Это намного важнее, чем сохранение нескольких наносекунд в коде JavaScript.

Джон Бенедикто
источник
5
В частности, в javascript семантика и удобочитаемость (и, следовательно, удобство обслуживания) превосходят любые локализованные различия в производительности между if..elseи switchвызванные уникальным сочетанием компьютерной версии браузера и ОС.
jball
2
Я не знаю, согласен ли я, это действительно можно заметить, если использовать его в цикле, скажем, с большой базой данных, обходом дерева и т. Д.
ghoppe
2
Я определенно не согласен. По мере того как веб-приложения становятся все более и более сложными, эта разница может быть значительной для приложения и может меняться в зависимости от браузеров.
Joshvermaire
7
Важно написать чистый, поддерживаемый код. Когда проблема производительности замечена - профиль. Затем определите, какой код исправить. Не жертвуйте ремонтопригодностью для предполагаемых проблем с производительностью.
Джон Бенедикто
3
'if else if else ...' - это O (n), а 'switch' - это либо O (1), либо O (log (n)). Как вы можете честно заявить, что разница никогда не бывает достаточно большой? Имейте в виду миллион случаев (легко возможно, если код генерируется), и вы обязательно заметите это, если не сказать больше.
dragonroot
6

Помимо синтаксиса, переключение может быть реализовано с использованием дерева, которое его создает O(log n), тогда как if / else должно быть реализовано с O(n)процедурным подходом. Чаще всего они обрабатываются процедурно, и единственное различие заключается в синтаксисе, и, кроме того, это действительно имеет значение - разве вы в любом случае статически набираете 10 000 случаев if / else?

Эван Кэрролл
источник
7 лет спустя ... Я не вижу, как возможна реализация дерева, кроме случая постоянных числовых значений регистра).
Эд Стауб
4

Ответ Пойнти предполагает использование литерала объекта в качестве альтернативы switchили if/ else. Мне тоже нравится этот подход, но код в ответе создает новый mapобъект каждый раз, когда dispatchвызывается функция:

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();
}

Если mapсодержит большое количество записей, это может привести к значительным накладным расходам. Лучше настроить карту действий только один раз, а затем каждый раз использовать уже созданную карту, например:

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();
}
Майкл Гири
источник
3

Есть ли разница в производительности в Javascript между оператором switch и if ... else if .... else?

Я так не думаю, switchполезно / коротко, если вы хотите предотвратить несколько if-elseсостояний.

Поведение переключателя и если ... еще, если ... еще отличается в разных браузерах? (FireFox, IE, Chrome, Opera, Safari)

Поведение одинаково во всех браузерах :)

Sarfraz
источник
5
switch is useful/short if you want prevent multiple if-else conditions.Да, сэр, отличный пост.
NiCk Ньюман
1
  1. Верстак может привести к некоторым очень небольшим различиям в некоторых случаях, но способ обработки в любом случае зависит от браузера, поэтому не стоит беспокоиться
  2. Из-за разных способов обработки
  3. Вы не можете назвать это браузером, если поведение все равно будет другим
Koen
источник