Мне было интересно, есть ли разница в производительности между использованием именованных функций и анонимных функций в Javascript?
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = function() {
// do something
};
}
против
function myEventHandler() {
// do something
}
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = myEventHandler;
}
Первый более аккуратный, поскольку он не загромождает ваш код редко используемыми функциями, но имеет ли значение то, что вы повторно объявляете эту функцию несколько раз?
Ответы:
Проблема с производительностью здесь заключается в стоимости создания нового объекта функции на каждой итерации цикла, а не в том, что вы используете анонимную функцию:
for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = function() { // do something }; }
Вы создаете тысячу различных функциональных объектов, даже если они имеют один и тот же код и не привязаны к лексической области видимости ( закрытие ). С другой стороны, следующее кажется более быстрым, потому что оно просто назначает одну и ту же ссылку на функцию элементам массива по всему циклу:
function myEventHandler() { // do something } for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = myEventHandler; }
Если вы должны были создать анонимную функцию перед входом в цикл, а затем назначить ссылки на нее элементам массива только внутри цикла, вы обнаружите, что нет никакой производительности или семантической разницы по сравнению с версией именованной функции:
var handler = function() { // do something }; for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = handler; }
Короче говоря, использование анонимных функций по сравнению с именованными функциями не требует заметных затрат производительности.
Кроме того, сверху может показаться, что нет никакой разницы между:
function myEventHandler() { /* ... */ }
а также:
var myEventHandler = function() { /* ... */ }
Первое - это объявление функции, тогда как второе - это присвоение переменной анонимной функции. Хотя может показаться, что они имеют одинаковый эффект, JavaScript обрабатывает их несколько иначе. Чтобы понять разницу, я рекомендую прочитать « Неоднозначность объявления функции JavaScript ».
Фактическое время выполнения для любого подхода в значительной степени будет определяться реализацией компилятора и среды выполнения браузером. Для полного сравнения производительности современных браузеров посетите сайт JS Perf.
источник
node.js
веб-приложений лучше создавать функции вне потока запросов и передавать их как обратные вызовы, чем создавать анонимные обратные вызовы?Вот мой тестовый код:
var dummyVar; function test1() { for (var i = 0; i < 1000000; ++i) { dummyVar = myFunc; } } function test2() { for (var i = 0; i < 1000000; ++i) { dummyVar = function() { var x = 0; x++; }; } } function myFunc() { var x = 0; x++; } document.onclick = function() { var start = new Date(); test1(); var mid = new Date(); test2(); var end = new Date(); alert ("Test 1: " + (mid - start) + "\n Test 2: " + (end - mid)); }
Результаты:
Тест 1: 142 мс, Тест 2: 1983 мс.
Похоже, что JS-движок не распознает одну и ту же функцию в Test2 и каждый раз компилирует ее.
источник
В качестве общего принципа разработки следует избегать повторения одного и того же кода несколько раз. Вместо этого вы должны превратить общий код в функцию и выполнить эту (общую, хорошо протестированную, легко модифицируемую) функцию из нескольких мест.
Если (в отличие от того, что вы делаете из своего вопроса) вы объявляете внутреннюю функцию один раз и используете этот код один раз (и в вашей программе нет ничего идентичного), то, вероятно, автономная функция (это предположение, ребята) обрабатывается таким же образом компилятор как обычная именованная функция.
Это очень полезная функция в определенных случаях, но не должна использоваться во многих ситуациях.
источник
Я бы не ожидал большой разницы, но если она есть, она, скорее всего, будет зависеть от скриптового движка или браузера.
Если вы обнаружите, что код легче анализировать, производительность не является проблемой, если вы не ожидаете вызова функции миллионы раз.
источник
Где мы можем повлиять на производительность, так это в операции объявления функций. Вот эталон объявления функций внутри или вне контекста другой функции:
http://jsperf.com/function-context-benchmark
В Chrome операция выполняется быстрее, если мы объявляем функцию снаружи, но в Firefox все наоборот.
В другом примере мы видим, что если внутренняя функция не является чистой функцией, у нее будет недостаток производительности также в Firefox: http://jsperf.com/function-context-benchmark-3
источник
Что определенно сделает ваш цикл быстрее в различных браузерах, особенно в браузерах IE, так это цикл следующим образом:
for (var i = 0, iLength = imgs.length; i < iLength; i++) { // do something }
Вы ввели произвольную 1000 в условие цикла, но вы понимаете мое отклонение, если хотите пройти по всем элементам в массиве.
источник
ссылка почти всегда будет медленнее, чем то, на что она ссылается. Подумайте об этом так - допустим, вы хотите напечатать результат сложения 1 + 1. Что имеет больше смысла:
alert(1 + 1);
или
a = 1; b = 1; alert(a + b);
Я понимаю, что это действительно упрощенный взгляд на это, но он иллюстративный, не так ли? Используйте ссылку только в том случае, если она будет использоваться несколько раз - например, какой из этих примеров имеет больше смысла:
$(a.button1).click(function(){alert('you clicked ' + this);}); $(a.button2).click(function(){alert('you clicked ' + this);});
или
function buttonClickHandler(){alert('you clicked ' + this);} $(a.button1).click(buttonClickHandler); $(a.button2).click(buttonClickHandler);
Второй вариант лучше, даже если в нем больше линий. Надеюсь, все это будет полезно. (а синтаксис jquery никого не скинул)
источник
@nickf
(хотелось бы, чтобы у меня был представитель, чтобы просто прокомментировать, но я только что нашел этот сайт)
Я хочу сказать, что здесь есть путаница между именованными / анонимными функциями и вариантом использования выполнения + компиляции в итерации. Как я проиллюстрировал, разница между anon + named незначительна сама по себе - я говорю, что это ошибочный вариант использования.
Мне это кажется очевидным, но если нет, то лучший совет - «не делайте глупостей» (одним из которых является постоянное смещение блока + создание объекта в этом варианте использования), а если вы не уверены, протестируйте!
источник
ДА! Анонимные функции быстрее обычных. Возможно, если скорость имеет первостепенное значение ... более важно, чем повторное использование кода, подумайте об использовании анонимных функций.
Здесь есть действительно хорошая статья об оптимизации javascript и анонимных функций:
http://dev.opera.com/articles/view/efficient-javascript/?page=2
источник
Анонимные объекты быстрее, чем именованные. Но вызов дополнительных функций стоит дороже и до некоторой степени затмевает любую экономию, которую вы можете получить от использования анонимных функций. Каждая вызываемая функция добавляет к стеку вызовов, что приводит к небольшим, но нетривиальным накладным расходам.
Но если вы не пишете процедуры шифрования / дешифрования или что-то подобное, чувствительное к производительности, как отметили многие другие, всегда лучше оптимизировать для элегантного, легкого для чтения кода, чем для быстрого кода.
Предполагая, что вы пишете код с хорошей архитектурой, вопросы скорости должны лежать в сфере ответственности тех, кто пишет интерпретаторы / компиляторы.
источник
@nickf
Однако это довольно бессмысленный тест, вы сравниваете время выполнения и компиляции там, что, очевидно, будет стоить метода 1 (компилируется N раз, в зависимости от движка JS) с методом 2 (компилируется один раз). Я не могу представить себе JS-разработчика, который прошел бы испытательный срок для написания кода таким образом.
Гораздо более реалистичным подходом является анонимное присвоение, поскольку на самом деле вы используете для своего документа метод. Onclick больше похож на следующий, который на самом деле мягко отдает предпочтение методу anon.
Используя аналогичную вашу среду тестирования:
function test(m) { for (var i = 0; i < 1000000; ++i) { m(); } } function named() {var x = 0; x++;} var test1 = named; var test2 = function() {var x = 0; x++;} document.onclick = function() { var start = new Date(); test(test1); var mid = new Date(); test(test2); var end = new Date(); alert ("Test 1: " + (mid - start) + "ms\n Test 2: " + (end - mid) + "ms"); }
источник
Как указано в комментариях к ответу @nickf: ответ на
просто да. Но, как показывает его JS perf, он не медленнее в миллион раз, показывая, что со временем он действительно становится быстрее.
Для меня более интересный вопрос:
Если функция выполняет сложное вычисление, время для создания объекта функции, скорее всего, незначительно. Но как насчет лишних затрат на создание в случаях, когда запуск выполняется быстро? Например:
// Variant 1: create once function adder(a, b) { return a + b; } for (var i = 0; i < 100000; ++i) { var x = adder(412, 123); } // Variant 2: repeated creation via function statement for (var i = 0; i < 100000; ++i) { function adder(a, b) { return a + b; } var x = adder(412, 123); } // Variant 3: repeated creation via function expression for (var i = 0; i < 100000; ++i) { var x = (function(a, b) { return a + b; })(412, 123); }
Этот JS Perf показывает, что создание функции только один раз происходит быстрее, чем ожидалось. Однако даже при очень быстрой операции, такой как простое добавление, накладные расходы на многократное создание функции составляют всего несколько процентов.
Разница, вероятно, становится существенной только в тех случаях, когда создание объекта функции является сложным, но при этом сохраняется незначительное время выполнения, например, если все тело функции заключено в файл
if (unlikelyCondition) { ... }
.источник