Eu estive pensando, existe uma diferença de desempenho entre o uso de funções nomeadas e funções anônimas em Javascript?
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = function() {
// do something
};
}
vs
function myEventHandler() {
// do something
}
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = myEventHandler;
}
O primeiro é mais organizado, pois não confunde seu código com funções raramente usadas, mas faz diferença se você está declarando novamente essa função várias vezes?
Respostas:
O problema de desempenho aqui é o custo de criar um novo objeto de função a cada iteração do loop e não o fato de você usar uma função anônima:
for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = function() { // do something }; }
Você está criando milhares de objetos de função distintos, embora eles tenham o mesmo corpo de código e nenhuma vinculação ao escopo léxico ( encerramento ). O seguinte parece mais rápido, por outro lado, porque simplesmente atribui a mesma referência de função aos elementos da matriz em todo o loop:
function myEventHandler() { // do something } for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = myEventHandler; }
Se você criasse a função anônima antes de entrar no loop, apenas atribua referências a ela aos elementos da matriz enquanto estiver dentro do loop, você descobrirá que não há nenhuma diferença de desempenho ou semântica em comparação com a versão da função nomeada:
var handler = function() { // do something }; for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = handler; }
Resumindo, não há custo de desempenho observável no uso de funções anônimas em vez de nomeadas.
Como um aparte, pode parecer de cima que não há diferença entre:
function myEventHandler() { /* ... */ }
e:
var myEventHandler = function() { /* ... */ }
O primeiro é uma declaração de função, enquanto o último é uma atribuição de variável a uma função anônima. Embora possam parecer ter o mesmo efeito, o JavaScript os trata de maneira um pouco diferente. Para entender a diferença, recomendo a leitura, “ Ambigüidade da declaração da função JavaScript ”.
O tempo de execução real para qualquer abordagem será amplamente ditado pela implementação do navegador do compilador e do tempo de execução. Para uma comparação completa do desempenho do navegador moderno, visite o site JS Perf
fonte
node.js
aplicativos da Web, é melhor criar as funções fora do fluxo de solicitação e passá-las como callbacks do que criar callbacks anônimos?Este é meu código de teste:
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)); }
Os resultados:
Teste 1: 142ms Teste 2: 1983ms
Parece que o mecanismo JS não reconhece que é a mesma função em Test2 e a compila todas as vezes.
fonte
Como princípio geral de design, você deve evitar implementar o mesmo código várias vezes. Em vez disso, você deve transformar o código comum em uma função e executar essa função (geral, bem testada, fácil de modificar) de vários lugares.
Se (ao contrário do que você infere de sua pergunta) você está declarando a função interna uma vez e usando esse código uma vez (e não tem mais nada idêntico em seu programa), então uma função anônima provavelmente (isso é um palpite, pessoal) é tratada da mesma maneira pelo compilador como uma função nomeada normal.
É um recurso muito útil em casos específicos, mas não deve ser usado em muitas situações.
fonte
Eu não esperaria muita diferença, mas se houver uma, provavelmente irá variar de acordo com o mecanismo de script ou navegador.
Se você achar o código mais fácil de entender, o desempenho não é um problema, a menos que você espere chamar a função milhões de vezes.
fonte
Onde podemos ter um impacto no desempenho é na operação de declarar funções. Aqui está um benchmark de declarar funções dentro do contexto de outra função ou fora:
http://jsperf.com/function-context-benchmark
No Chrome a operação é mais rápida se declararmos a função externamente, mas no Firefox é o contrário.
Em outro exemplo, vemos que se a função interna não for uma função pura, ela terá uma falta de desempenho também no Firefox: http://jsperf.com/function-context-benchmark-3
fonte
O que definitivamente tornará seu loop mais rápido em uma variedade de navegadores, especialmente navegadores do IE, é o seguinte:
for (var i = 0, iLength = imgs.length; i < iLength; i++) { // do something }
Você colocou um 1000 arbitrário na condição de loop, mas entendeu minha sugestão se quisesse passar por todos os itens do array.
fonte
uma referência quase sempre será mais lenta do que aquilo a que se refere. Pense desta forma - digamos que você deseja imprimir o resultado da adição de 1 + 1. O que faz mais sentido:
alert(1 + 1);
ou
a = 1; b = 1; alert(a + b);
Percebo que é uma forma muito simplista de ver as coisas, mas é ilustrativo, certo? Use uma referência apenas se ela for ser usada várias vezes - por exemplo, qual destes exemplos faz mais sentido:
$(a.button1).click(function(){alert('you clicked ' + this);}); $(a.button2).click(function(){alert('you clicked ' + this);});
ou
function buttonClickHandler(){alert('you clicked ' + this);} $(a.button1).click(buttonClickHandler); $(a.button2).click(buttonClickHandler);
O segundo é uma prática melhor, mesmo que tenha mais linhas. Espero que tudo isso seja útil. (e a sintaxe jquery não confundiu ninguém)
fonte
@nickf
(gostaria de ter o representante para apenas comentar, mas acabei de encontrar este site)
Meu ponto é que há confusão aqui entre funções nomeadas / anônimas e o caso de uso de execução + compilação em uma iteração. Como ilustrei, a diferença entre anon + named é insignificante em si - estou dizendo que é o caso de uso que está com defeito.
Parece óbvio para mim, mas se não, acho que o melhor conselho é "não faça coisas idiotas" (das quais o deslocamento de bloco constante + criação de objeto deste caso de uso é um) e se você não tiver certeza, teste!
fonte
SIM! As funções anônimas são mais rápidas do que as funções regulares. Talvez, se a velocidade for de extrema importância ... mais importante do que a reutilização de código, considere o uso de funções anônimas.
Há um artigo muito bom sobre a otimização de funções javascript e anônimas aqui:
http://dev.opera.com/articles/view/efficient-javascript/?page=2
fonte
Objetos anônimos são mais rápidos do que objetos nomeados. Mas chamar mais funções é mais caro e em um grau que eclipsa qualquer economia que você possa obter com o uso de funções anônimas. Cada função chamada adiciona à pilha de chamadas, o que introduz uma pequena, mas não trivial, quantidade de sobrecarga.
Mas, a menos que você esteja escrevendo rotinas de criptografia / descriptografia ou algo similarmente sensível ao desempenho, como muitos outros notaram, é sempre melhor otimizar para um código elegante e fácil de ler em vez de um código rápido.
Supondo que você esteja escrevendo um código bem arquitetado, as questões de velocidade devem ser responsabilidade de quem está escrevendo os interpretadores / compiladores.
fonte
@nickf
Este é um teste um tanto estúpido, você está comparando o tempo de execução e compilação lá, que obviamente custará o método 1 (compila N vezes, dependendo do mecanismo JS) com o método 2 (compila uma vez). Não consigo imaginar um desenvolvedor JS que passaria pelo período probatório escrevendo código dessa maneira.
Uma abordagem muito mais realista é a atribuição anônima, já que, na verdade, você está usando para o seu documento. O método onclick é mais parecido com o seguinte, que na verdade favorece levemente o método anon.
Usando uma estrutura de teste semelhante à sua:
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"); }
fonte
Conforme apontado nos comentários para @nickf answer: A resposta para
é simplesmente sim. Mas, como mostra seu desempenho em JS, não é mais lento por um milhão, mostrando que na verdade fica mais rápido com o tempo.
A questão mais interessante para mim é:
Se uma função executa um cálculo complexo, o tempo para criar o objeto de função é provavelmente insignificante. Mas e quanto à sobrecarga de criação nos casos em que a execução é rápida? Por exemplo:
// 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); }
Este JS Perf mostra que criar a função apenas uma vez é mais rápido como o esperado. No entanto, mesmo com uma operação muito rápida como um simples acréscimo, a sobrecarga de criar a função repetidamente é de apenas alguns por cento.
A diferença provavelmente só se torna significativa nos casos em que a criação do objeto de função é complexa, enquanto mantém um tempo de execução insignificante, por exemplo, se todo o corpo da função é agrupado em um
if (unlikelyCondition) { ... }
.fonte