Je me suis demandé s'il y avait une différence de performances entre l'utilisation de fonctions nommées et de fonctions anonymes en Javascript?
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = function() {
// do something
};
}
contre
function myEventHandler() {
// do something
}
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = myEventHandler;
}
Le premier est plus ordonné car il n'encombre pas votre code avec des fonctions rarement utilisées, mais est-il important que vous re-déclariez cette fonction plusieurs fois?
Réponses:
Le problème de performances ici est le coût de création d'un nouvel objet fonction à chaque itération de la boucle et non le fait que vous utilisez une fonction anonyme:
for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = function() { // do something }; }
Vous créez un millier d'objets de fonction distincts même s'ils ont le même corps de code et aucune liaison avec la portée lexicale ( fermeture ). Ce qui suit semble plus rapide, en revanche, car il affecte simplement la même référence de fonction aux éléments du tableau tout au long de la boucle:
function myEventHandler() { // do something } for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = myEventHandler; }
Si vous deviez créer la fonction anonyme avant d'entrer dans la boucle, puis attribuez-lui des références uniquement aux éléments du tableau à l'intérieur de la boucle, vous constaterez qu'il n'y a aucune différence de performance ou de sémantique par rapport à la version de la fonction nommée:
var handler = function() { // do something }; for (var i = 0; i < 1000; ++i) { myObjects[i].onMyEvent = handler; }
En bref, il n'y a aucun coût de performance observable à l'utilisation de fonctions anonymes sur des fonctions nommées.
En passant, il peut sembler d'en haut qu'il n'y a pas de différence entre:
function myEventHandler() { /* ... */ }
et:
var myEventHandler = function() { /* ... */ }
Le premier est une déclaration de fonction tandis que le second est une affectation de variable à une fonction anonyme. Bien qu'ils semblent avoir le même effet, JavaScript les traite légèrement différemment. Pour comprendre la différence, je vous recommande de lire « ambiguïté de déclaration de fonction JavaScript ».
Le temps d'exécution réel de toute approche sera en grande partie dicté par l'implémentation du compilateur et du runtime par le navigateur. Pour une comparaison complète des performances des navigateurs modernes, visitez le site JS Perf
la source
node.js
d'applications Web, il est préférable de créer les fonctions en dehors du flux de requêtes et de les transmettre en tant que rappels, que de créer des rappels anonymes?Voici mon code de test:
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)); }
Les résultats:
Test 1: 142ms Test 2: 1983ms
Il semble que le moteur JS ne reconnaît pas qu'il s'agit de la même fonction dans Test2 et la compile à chaque fois.
la source
En tant que principe de conception général, vous devez éviter d'implémenter le même code plusieurs fois. Au lieu de cela, vous devez extraire du code commun dans une fonction et exécuter cette fonction (générale, bien testée, facile à modifier) à partir de plusieurs endroits.
Si (contrairement à ce que vous déduisez de votre question) vous déclarez la fonction interne une fois et en utilisant ce code une fois (et que vous avez rien d' autre identique dans votre programme) , puis une fonction anonomous probablement (thats un gens guess) obtient traité de la même manière par le compilateur en tant que fonction nommée normale.
C'est une fonctionnalité très utile dans des cas spécifiques, mais ne devrait pas être utilisée dans de nombreuses situations.
la source
Je ne m'attendrais pas à beaucoup de différence, mais s'il y en a une, elle variera probablement en fonction du moteur de script ou du navigateur.
Si vous trouvez le code plus facile à utiliser, les performances ne sont pas un problème, sauf si vous prévoyez d'appeler la fonction des millions de fois.
la source
Là où nous pouvons avoir un impact sur les performances, c'est dans l'opération de déclaration des fonctions. Voici un benchmark de la déclaration de fonctions dans le contexte d'une autre fonction ou à l'extérieur:
http://jsperf.com/function-context-benchmark
Dans Chrome, l'opération est plus rapide si nous déclarons la fonction à l'extérieur, mais dans Firefox, c'est le contraire.
Dans un autre exemple, nous voyons que si la fonction interne n'est pas une fonction pure, elle manquera également de performances dans Firefox: http://jsperf.com/function-context-benchmark-3
la source
Ce qui rendra certainement votre boucle plus rapide sur une variété de navigateurs, en particulier les navigateurs IE, se déroule comme suit:
for (var i = 0, iLength = imgs.length; i < iLength; i++) { // do something }
Vous avez mis un 1000 arbitraire dans la condition de boucle, mais vous obtenez ma dérive si vous vouliez parcourir tous les éléments du tableau.
la source
une référence sera presque toujours plus lente que la chose à laquelle elle fait référence. Pensez-y de cette façon - disons que vous voulez imprimer le résultat de l'ajout de 1 + 1. Ce qui est plus logique:
alert(1 + 1);
ou
a = 1; b = 1; alert(a + b);
Je me rends compte que c'est une façon vraiment simpliste de voir les choses, mais c'est illustratif, non? N'utilisez une référence que si elle doit être utilisée plusieurs fois - par exemple, lequel de ces exemples a le plus de sens:
$(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);
Le second est une meilleure pratique, même s'il y a plus de lignes. J'espère que tout cela est utile. (et la syntaxe jquery n'a découragé personne)
la source
@nickf
(j'aurais aimé avoir le représentant pour commenter, mais je viens de trouver ce site)
Mon point est qu'il existe ici une confusion entre les fonctions nommées / anonymes et le cas d'utilisation de l'exécution + compilation dans une itération. Comme je l'ai illustré, la différence entre anon + named est négligeable en soi - je dis que c'est le cas d'utilisation qui est défectueux.
Cela me semble évident, mais sinon je pense que le meilleur conseil est de "ne pas faire de choses stupides" (dont le décalage de bloc constant + création d'objet de ce cas d'utilisation en fait partie) et si vous n'êtes pas sûr, testez!
la source
OUI! Les fonctions anonymes sont plus rapides que les fonctions normales. Peut-être que si la vitesse est de la plus haute importance ... plus importante que la réutilisation du code, envisagez d'utiliser des fonctions anonymes.
Il y a un très bon article sur l'optimisation des fonctions javascript et anonymes ici:
http://dev.opera.com/articles/view/efficient-javascript/?page=2
la source
Les objets anonymes sont plus rapides que les objets nommés. Mais appeler plus de fonctions coûte plus cher, et dans une mesure qui éclipse les économies que vous pourriez obtenir en utilisant des fonctions anonymes. Chaque fonction appelée s'ajoute à la pile d'appels, ce qui introduit une petite quantité non négligeable de frais généraux.
Mais à moins que vous n'écriviez des routines de cryptage / décryptage ou quelque chose de similaire sensible aux performances, comme beaucoup d'autres l'ont noté, il est toujours préférable d'optimiser pour un code élégant et facile à lire sur un code rapide.
En supposant que vous écrivez un code bien conçu, les problèmes de vitesse devraient être la responsabilité de ceux qui écrivent les interprètes / compilateurs.
la source
@nickf
C'est un test assez fatiguant cependant, vous comparez le temps d'exécution et de compilation là-bas qui va évidemment coûter la méthode 1 (compile N fois, selon le moteur JS) avec la méthode 2 (compile une fois). Je ne peux pas imaginer un développeur JS qui réussirait sa probation en écrivant du code de cette manière.
Une approche beaucoup plus réaliste est l'affectation anonyme, car en fait, vous utilisez pour votre méthode document.onclick ressemble plus à la suivante, qui en fait favorise légèrement la méthode anon.
En utilisant un cadre de test similaire au vôtre:
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"); }
la source
Comme indiqué dans les commentaires à @nickf answer: La réponse à
est simplement oui. Mais comme le montre sa performance JS, elle n'est pas plus lente d'un facteur d'un million, ce qui montre qu'elle s'accélère réellement avec le temps.
La question la plus intéressante pour moi est:
Si une fonction effectue un calcul complexe, le temps de création de l'objet fonction est très probablement négligeable. Mais qu'en est-il de la surcharge de création dans les cas où l' exécution est rapide? Par exemple:
// 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); }
Ce JS Perf montre que créer la fonction une seule fois est plus rapide que prévu. Cependant, même avec une opération très rapide comme un simple ajout, la surcharge liée à la création répétée de la fonction n'est que de quelques pour cent.
La différence ne devient probablement significative que dans les cas où la création de l'objet fonction est complexe, tout en conservant un temps d'exécution négligeable, par exemple, si le corps de la fonction entière est enveloppé dans un fichier
if (unlikelyCondition) { ... }
.la source