2009-09-23 4 views
1

J'ai regardé les discussions techniques de Google Speed Up Your Javascript et en parlant de boucles, le locuteur mentionne de rester loin des itérations basées sur la fonction telles que jQuery.each() (entre autres, vers 24:05 dans la vidéo). Il explique brièvement pourquoi les éviter, ce qui est logique, mais je ne comprends pas très bien quelle serait une alternative. Dites, dans le cas où je veux parcourir une colonne de cellules de tableau et utiliser la valeur pour manipuler la valeur de la cellule adjacente (juste un exemple rapide). Quelqu'un peut-il expliquer et donner un exemple d'alternative à l'itération basée sur la fonction?Alternatives à l'itération basée sur la fonction javascript (par exemple jQuery.each())

Répondre

4

Juste une simple boucle devrait être plus rapide si vous avez besoin de boucle.

var l = collection.length; 
for (var i = 0; i<l; i++) { 
    //do stuff 
} 

Mais, juste parce qu'il est plus rapide ne signifie pas qu'il est toujours important qu'il en est ainsi.

Cela s'exécute sur le client, pas sur le serveur, vous n'avez donc pas besoin de vous soucier de la mise à l'échelle avec le nombre d'utilisateurs, et s'il est rapide avec .each(), laissez-le. Mais, si c'est lent, une boucle for pourrait l'accélérer.

+0

La voie de jeûne du itérer en javascript est do { // code être exécuté } while (--currentIndex) Bien sûr, vous ne pouvez l'utiliser que lorsque l'ordre n'est pas important (ou que l'ordre inverse est souhaitable) – klaaspieter

+0

J'utilise normalement 'for (var i = foo.length; i-- ;) {} '; une boucle 'do..while' avec pré-décrémentation pourrait être plus rapide, mais en pratique la différence compte rarement – Christoph

+0

@klaaspieter, vous pouvez simplement inverser l'ordre en utilisant ++ currentIndex et, avant le bloc, faire currentIndex * = -1 ; – Dykam

4

Ye olde boucle for

2

Il me semble que ce serait le cas cette itération par fonction serait légèrement plus lent en raison de la 1) les frais généraux de la fonction elle-même, 2) les frais généraux de la fonction de rappel étant créé et exécuté N fois, et 3) la profondeur supplémentaire dans la chaîne de portée. Cependant, je pensais que je ferais une référence rapide juste pour les coups de pied. Il s'avère, au moins dans mon cas de test simple, que l'itération basée sur la fonction était plus rapide. Voici le code et les résultats

Code de référence Test

// Function based iteration method 
var forEach = function(_a, callback) { 
    for (var _i=0; _i<_a.length; _i++) { 
    callback(_a[_i], _i); 
    } 
} 

// Generate a big ass array with numbers 0..N 
var a = [], LENGTH = 1024 * 10; 
for (var i=0; i<LENGTH; i++) { a.push(i); } 

console.log("Array length: %d", LENGTH); 

// Test 1: function-based iteration 
console.info("function-base iteration"); 
var end1 = 0, start1 = new Date().getTime(); 

var sum1 = 0; 
forEach(a, function(value, index) { sum1 += value; }); 

end1 = new Date().getTime(); 
console.log("Time: %sms; Sum: %d", end1 - start1, sum1); 

// Test 2: normal for-loop iteration 
console.info("Normal for-loop"); 
var end2 = 0, start2 = new Date().getTime(); 

var sum2 = 0; 
for (var j=0; j<a.length; j++) { sum2 += a[j]; } 

end2 = new Date().getTime(); 
console.log("Time: %sms; Sum: %d", end2 - start2, sum2); 

Chaque test résume tout le tableau qui est simpliste, mais quelque chose qui peut être vu de manière réaliste dans une sorte de scénario de la vie réelle.

Résultats pour 3,5 FF

Array length: 10240 
function-base iteration 
Time: 9ms; Sum: 52423680 
Normal for-loop 
Time: 22ms; Sum: 52423680 

avère qu'une itération for de base a été plus rapide dans ce cas de test. Je n'ai pas encore regardé la vidéo, mais je vais y jeter un coup d'œil et voir s'il diffère quelque part qui rendrait les itérations basées sur les fonctions plus lentes. Edit: Ce n'est en aucun cas le résultat final, c'est-à-dire tous les résultats d'un seul moteur et d'un seul cas d'essai. Je m'attendais à ce que les résultats soient inversés (l'itération basée sur les fonctions étant plus lente), mais il est intéressant de voir comment certains navigateurs ont fait des optimisations (qui peuvent ou non cibler spécifiquement ce style de JavaScript) afin que le l'opposé est vrai.

+0

C'est parce que vous avez utilisé "j CaffGeek

+0

Je suis pleinement conscient de cette optimisation; cependant, il ne devrait pas avoir d'influence sur ce test car vous remarquerez que les deux boucles 'for' ont une structure et un manque d'optimisation identiques. Mais, comme le premier test a montré des résultats inattendus, je vais l'exécuter à nouveau avec cette optimisation pour voir si cela change quelque chose, mais je ne suis pas convaincu à ce point que ça le fera. Les deux itérations devraient diminuer d'un montant similaire. –

+0

@chad Comme je le soupçonnais, cette optimisation n'a pas changé les résultats des tests de manière significative. En fait, je considérerais cela comme une fausse optimisation avec cette structure de données. Pour les structures de données en direct (comme les conteneurs Dom), cette optimisation est utile. –

0

Si l'ordre de bouclage n'a pas d'importance, les éléments suivants doivent être les plus rapides car vous n'avez besoin que d'une seule variable locale; aussi, décrémenter le compteur et les limites vérification sont faites avec une seule instruction:

var i = foo.length; 
if(i) do { // check for i != 0 
    // do stuff with `foo[i]` 
} while(--i); 

Ce que j'utilise normalement est la suivante:

for(var i = foo.length; i--;) { 
    // do stuff with `foo[i]` 
} 

Il est potentiellement plus lente que la version précédente (post-vs pré -decrement, for vs while), mais plus lisible.

1

La méthode la plus rapide pour itérer consiste à réduire les tâches que vous effectuez dans la boucle. Faites sortir les éléments de l'itération et minimisez les recherches/incréments dans la boucle, par ex.

var i = arr.length; 

while (i--) { 
    console.log("Item no "+i+" is "+arr[i]); 
} 

NB! En testant sur la dernière version de Safari (avec WebKit nightly), Chrome et Firefox, vous remarquerez que peu importe le type de boucle que vous choisissez si ce n'est pas for each ou for in (ou pire, toutes les fonctions dérivées construites sur eux).

De plus, ce qui se révèle, est que la boucle for suivante est très légèrement plus vite que l'option ci-dessus:

var l = arr.length; 

for (var i=l; i--;) { 
    console.log("Item no "+i+" is "+arr[i]); 
} 
Questions connexes