69 votes

Boucle $.each() vs for() - et performances

Ce sont principalement des choses que je me suis demandées, peut-être que quelqu'un peut me donner un peu plus d'informations à leur sujet, je vais partager ce que j'ai remarqué jusqu'à présent !

La première chose que je me suis demandée... y a-t-il une différence bonne ou raison à utiliser :

$('element').each(function (i, el) { });

-- contre

$.each($('element'), function (i, el) { });

En regardant la documentation de jQuery, je ne vois aucune raison de choisir l'un ou l'autre (peut-être connaissez-vous un exemple ou des choses supplémentaires que l'un peut faire par rapport à l'autre).

Mais le plus important, c'est que je m'inquiète vitesse aquí

// As opposed to $.each() looping through a jQuery object
// -- 8x faster 
for (var i = 0, $('.whatever').length; i < len; i++) {
    $('.whatever')[i] // do stuff
}

Si vous regardez ce jsFiddle DEMO ici vous verrez que la différence de vitesse est équivalente avec l'un ou l'autre, mais plus important encore, j'ai l'impression que je devrais siempre utiliser for() des boucles...

J'étais en train de faire des tests unitaires (en bouclant chacune des 5 fonctions de scénario différentes, 50 000 fois), en bouclant simplement un ensemble d'éléments de liste, et en définissant une fonction data-newAttr rien de spécial.


QUESTION : : Je suppose que ma plus grande question est, pourquoi pas siempre utiliser des boucles for en itérant sur un objet ? Y a-t-il un intérêt à utiliser $.each() ? Utilisez-vous toujours les boucles for() même lorsque vous parcourez des objets jQuery ?

jsFiddle DEMO ici

Function type:                  Execution Time:
_testArea.each() + $(this)               1947   <-- using $(this) slows it down tremendously
$.each()         + $(this)               1940
_testArea.each() + el(plain JS)           458   <-- using the Element speeds things up
$.each()         + el(plain JS)           452
for() loop       + plainJS[0] iteration   236   <-- over 8x faster

C'est juste mon avis. :)

46voto

PPvG Points 4395

Une chose que .each() vous permet de faire ce qui ne peut pas être fait avec une for La boucle est enchaînement .

$('.rows').each(function(i, el) {
    // do something with ALL the rows
}).filter('.even').each(function(i, el) {
    // do something with the even rows
});

J'ai joué avec votre JSFiddle pour voir comment le chaînage influencerait les performances dans les cas où vous devez parcourir en boucle des sous-ensembles de l'ensemble original d'éléments appariés.

Le résultat n'était pas si inattendu que ça, bien que je pense que les frais généraux de end() a été exagérée ici en raison de la combinaison de quelques éléments et de nombreuses boucles. À part cela, les boucles en JS sont toujours légèrement plus rapides, mais il faut se demander si cela pèse dans la balance par rapport à l'amélioration de la lisibilité de la fonction .each() (et le chaînage) est discutable.

21voto

JayC Points 4879

Une chose que vous obtenez avec .each() est le scoping local automatique (parce que vous invoquez une fonction anonyme pour chaque objet), ce qui signifie que si vous créez encore plus de fonctions/fermetures/manipulateurs d'événements anonymes à chaque itération, vous n'avez jamais à vous soucier que vos manipulateurs partagent une variable. En d'autres termes, JavaScript ne se comporte pas comme les autres langages en ce qui concerne les scopes locaux, mais comme vous pouvez déclarer une variable n'importe où, cela peut parfois vous tromper.

En d'autres termes, c'est faux :

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx]
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
}

Chaque fois que l'un de ces objets invoquera son "someEvent" après cette boucle (veuillez noter que ceci est inventé), l'alerte dira toujours ce qui a été assigné en dernier lieu à idx qui devrait être (au moment où il est invoqué) someObjectArray.length ;

Pour être sûr de sauvegarder le bon index, vous devez déclarer une portée locale, créer une variable et l'assigner à cette variable pour l'utiliser.

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx];
   (function(){
       var localidx = idx;
       el.someEventHandler(function(){  
           alert( "this is element " + localidx);
       }); 
   })();
}

Comme vous pouvez le voir, c'est très moche, mais ça devrait fonctionner. Chaque gestionnaire d'événement reçoit sa propre copie de localidx

Maintenant, comparez cela à .each()

$(someObjectArray).each(function (idx, el) { 
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
});

C'est beaucoup plus simple, n'est-ce pas ?

9voto

Yeti Points 429

JQuery.each vs for-loop

Avantage jQuery.each :

  • S'intègre bien dans le code jQuery (chaînage et style).
  • Aucun souci de portée (les références à l'itérateur et à l'objet seront persistantes).
  • Peut être utilisé de manière universelle (pour tous les types d'objets et l'itération sur les clés des objets).

Avantages du for-loop :

  • Hautes performances (pour les jeux/animations/grands ensembles de données).
  • Contrôle total sur l'itérateur (sauter des éléments, couper des éléments de la liste, etc.).
  • Le for-loop fonctionnera toujours, car il n'y a pas de dépendance à jQuery.
  • La même syntaxe familière que la plupart des autres langages similaires.

Exemple de code

Voici un exemple de code qui montre comment je préfère itérer sur une liste.

var list = ['a', 'b', 'c', 'd', 'e', 'f'];

jQuery.each :

$.each(list, function(i, v)
{
    // code...
});

For-loop sans fermeture :

for(var i=0,v,n=list.length;i<n;i+=1)
{
    v = list[i];
    // code...
}

Pour-boucle avec fermeture :

for(var i=0,n=list.length;i<n;i+=1)
{
    (function(i, v)
    {
        // code...
    })(i, list[i]);
}

Note : Je vous suggère d'utiliser la boucle for standard, et de n'utiliser une fermeture que si nécessaire. Cependant, lorsque votre code ressemble plus à jQuery qu'à Javascript, il peut être plus facile d'utiliser simplement la fonction $.each . En cas de problèmes de performance, vous pourrez toujours y remédier par la suite.

5voto

op1ekun Points 1236

J'ai effectué quelques tests de performance simples il y a quelques temps http://jsperf.com/forloops3 . Il semble que s'en tenir au simple, vieux for loop (lorsque c'est possible) est la voie à suivre :)

4voto

James Black Points 26183

Lorsque je suis allé sur votre lien, voici les deux numéros que j'ai obtenus :

$.each() + el(plain JS) 401
for() loop + plainJS[0] iteration   377

Si la différence est minime, choisissez celle qui est la plus lisible, mais si vous avez des exigences très élevées en matière de temps, vous devrez peut-être choisir ce qui est le plus rapide.

Je vous suggère d'écrire votre programme pour utiliser trois méthodes différentes, les deux ci-dessus, puis d'utiliser le foreach que l'on trouve dans les nouvelles versions de javascript, et pour les navigateurs qui ne le supportent pas, vous pouvez l'ajouter comme prototype.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach

Vous savez quelles sont vos exigences et ce que votre programme fera. Il vous suffit donc d'écrire vos propres tests et de vous assurer qu'il répond aux exigences des navigateurs que vous prendrez en charge.

Pour votre première question, je choisirais $('element').each car il est beaucoup plus facile à lire, mais ce n'est que mon avis.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X