Я не вижу "ошибки" в вашем скрипте. Хотя я действительно не поощряю тестирование производительности таким образом, я все же могу сказать пару вещей, основываясь на своей интуиции. У меня нет надежных, хорошо проверенных результатов с контрольными группами и т. Д., Поэтому принимайте все, что я говорю, с щепоткой соли.
Теперь для меня вполне нормально предположить, что первый вариант пожирает пыль второго, потому что в js есть несколько вещей, более дорогих, чем переменный доступ:
- доступ к свойству объекта (предположительно O (1) хеш-таблица, но все же медленнее, чем доступ к переменной)
- вызов функции
Если мы посчитаем вызов функции и доступ к объекту:
- первый случай: 5 вызовов [к
getImportantValuePolymorphism
] x (1 доступ к объекту [к myClass
] + 1 вызов функции [к GetImportantValue
] ===> ВСЕГО из 10 вызовов функции + 5 объектов доступ
- второй случай: 5 вызовов [к
getImportantValueSwitch
] + 5 доступ к объекту [к MyClassEnum
] ===> ВСЕГО 5 вызовов функции + 5 доступ к объекту
Еще одна вещь, которую стоит упомянуть: в первом случае у вас есть функция, которая вызывает другую функцию, поэтому вы получаете цепочку областей видимости . Чистый эффект от этого незначителен, но все же отрицательно сказывается на производительности.
Если учесть все вышеперечисленные факторы, сначала будет медленнее. А сколько? На это непросто ответить, так как это будет зависеть от реализаций поставщиков, но в вашем случае это примерно в 25 раз медленнее в Chrome. Если предположить, что у нас удвоено количество вызовов функций в первом случае и цепочка областей действия , можно было бы ожидать, что она будет в 2 или 3 раза медленнее, но не 25.
Я полагаю, что это экспоненциальное снижение производительности связано с тем, что истощает цикл обработки событий , что означает, что когда вы даете синхронную задачу js, так как она однопоточна, если задача громоздкий цикл обработки событий не может продолжаться и застревает на секунду или около того. Этот вопрос возникает, когда люди видят странное поведение setTimeout или других асинхронных вызовов при удалении от целевого периода времени. Это, как я уже сказал, из-за того, что предыдущая синхронная задача занимает слишком много времени. В вашем случае у вас есть синхронный цикл for, который повторяется 10 миллионов раз.
Чтобы проверить мою гипотезу, уменьшите ITERATION_COUNT
до 100000, то есть в 100 раз меньше, вы увидите, что в chrome это соотношение будет уменьшаться с ~ 20 до ~ 2. Итак, суть 1: Часть наблюдаемой вами неэффективности проистекает из того факта, что вы исчерпали цикл обработки событий, но это все равно не меняет того факта, что первый вариант медленнее .
Чтобы проверить, что вызовы функций действительно являются узким местом, измените соответствующие части вашего скрипта на:
class1 = class1.GetImportantValue;
class2 = class2.GetImportantValue;
class3 = class3.GetImportantValue;
class4 = class4.GetImportantValue;
class5 = class5.GetImportantValue;
и для теста:
for (var i = 0; i < INTERATION_COUNT; i++) {
class1();
class2();
class3();
class4();
class5();
}
Результирующая скрипка: https://jsfiddle.net/ibowankenobi/oqzpfqcg/2/
На этот раз вы увидите, что первый из них быстрее, потому что он (5 вызовов функций) против (5 вызовов функций + 5 доступ к объектам).