Maison >interface Web >js tutoriel >Exploration approfondie des problèmes d'efficacité et d'optimisation associée des boucles for dans les compétences JavaScript_javascript

Exploration approfondie des problèmes d'efficacité et d'optimisation associée des boucles for dans les compétences JavaScript_javascript

WBOY
WBOYoriginal
2016-05-16 15:10:521594parcourir

Bibliothèque Underscore.js

Combien de boucles avez-vous écrites en une journée (semaine) ?

var i;
for(i = 0; i < someArray.length; i++) {
 var someThing = someArray[i];
 doSomeWorkOn(someThing);
}

C'est inoffensif, bien sûr, mais c'est moche et bizarre et il n'y a pas vraiment de quoi se plaindre. Mais cette façon d’écrire est trop banale.

var i,
 j;
for(i = 0; i < someArray.length; i++) {
 var someThing = someArray[i];
 for(j = 0; j < someThing.stuff.length; j++) {
   doSomeWorkOn(someThing.stuff[j]);
 }
}

Vous étendez du mauvais code, et avant de lancer un tas de si, vous êtes déjà fou.
Je n'ai pas écrit de boucle depuis deux ans.
"De quoi tu parles ?"
C'est vrai, une mauvaise blague. En fait, pas aucun (ok, j’en ai écrit quelques-uns), car je n’écris pas de boucles et mon code est plus facile à comprendre.
Comment?

_.each(someArray, function(someThing) {
 doSomeWorkOn(someThing);
})

Ou mieux encore :

_.each(someArray, doSomeWorkOn);

C'est ce que fait underscorejs. Propre, simple, lisible, court, pas de variables intermédiaires, pas de tonnes de points-virgules, simple et très élégant.
Voici quelques exemples supplémentaires.

var i,
 result = [];
for(i = 0; i < someArray.length; i++) {
 var someThing = someArray[i];
 // 打到这,我已经手疼了
 if(someThing.isAwesome === true) {
   result.push(someArray[i]);
 }
}

Encore une fois, un cas d'utilisation typique pour perdre du temps à utiliser des boucles. Même si ces sites font la promotion de la lutte contre le tabac et du végétarisme, je me sens indigné lorsque je vois ces codes. Regardez la manière simple de l’écrire.

var result = _.filter(someArray, function(someThing) {
 return someThing.isAwesome === true;
})

Comme le nom du filtre en trait de soulignement, seulement 3 lignes de code peuvent vous donner un nouveau tableau.
Ou souhaitez-vous convertir ces tableaux sous une autre forme ?

var result = _.map(someArray, function(someThing) {
 return trasformTheThing(someThing);
})

Les trois exemples ci-dessus sont suffisants dans la vie quotidienne, mais ces fonctions ne suffisent pas pour que le soulignement soit mis sur la table.

var grandTotal = 0,
 somePercentage = 1.07,
 severalNumbers = [33, 54, 42],
 i; // don't forget to hoist those indices;
for(i = 0; i < severalNumbers.length; i++) {
 var aNumber = severalNumbers[i];
 grandTotal += aNumber * somePercentage;
}

version soulignée

var somePercentage = 1.07,
 severalNumbers = [33, 54, 42],
 grandTotal;
grandTotal = _.reduce(severalNumbers, function(runningTotal, aNumber) {
 return runningTotal + (aNumber * somePercentage);
}, 0)

Cela peut sembler un peu étrange au début. J'ai vérifié la documentation sur la réduction et découvert son existence. Puisque je refuse d'utiliser des boucles, c'est mon premier choix. Les éléments ci-dessus ne sont qu'une introduction. La bibliothèque underscorejs possède également de nombreuses fonctions impressionnantes.

Défi de cycle sans utilisation de 30 jours.

N'utilisez aucune boucle pendant les 30 prochains jours. Si vous voyez un tas de choses désagréables et grossières, remplacez-les par chacune ou par une carte. Utilisez un peu plus de réduction.

Vous devez noter que Underscore est la passerelle vers la programmation fonctionnelle. Une manière visible et invisible. Une bonne voie à suivre.


Note OurJS* Les navigateurs modernes prennent actuellement en charge chacune des méthodes de filtrage, de mappage et de réduction, mais la bibliothèque de traits de soulignement peut atteindre la compatibilité avec les anciennes versions d'IE. Voici un exemple écrit à l'aide des méthodes natives ES5 :

.
[3,4,5,3,3].forEach(function(obj){
  console.log(obj);
});

[1,2,3,4,5].filter(function(obj){
  return obj < 3
});

[9,8,5,2,3,4,5].map(function(obj){
  return obj + 2;
});

[1,2,3,4,5].reduce(function(pre, cur, idx, arr) {
  console.log(idx);  //4 个循环: 2-5
  return pre + cur;
});  //15

//sort方法同样很有用
[9,8,5,2,3,4,5].sort(function(obj1, obj2){
  return obj1 - obj2;
});

for in et for boucle

Quelqu'un a souligné que l'efficacité de for in est bien inférieure à celle de for loop. Testons maintenant l'efficacité de l'utilisation de for in, for loop et forEach dans différents navigateurs lors du traitement de grands tableaux.

À l'heure actuelle, la plupart des logiciels open source mettront en cache la longueur du tableau dans la boucle for, car l'opinion courante est que certains navigateurs Array.length recalculeront la longueur du tableau à chaque fois, donc des variables temporaires sont généralement utilisées pour stocker la longueur du tableau. à l'avance, comme :

for (var idx = 0, len = testArray.length; idx < len; idx++) {
 //do sth.
}

Nous testerons également la différence de performances entre la mise en cache et l'absence de mise en cache.

Ajoutez également une opération de sommation dans chaque boucle de test pour montrer qu'il ne s'agit pas d'une boucle vide.

for (var idx = 0, len = testArray.length; idx < len; idx++) {
 //do sth.
}

Nous testerons également la différence de performances entre la mise en cache et l'absence de mise en cache.

Ajoutez également une opération de sommation dans chaque boucle de test pour montrer qu'il ne s'agit pas d'une boucle vide.

Le code de test est le suivant, cliquez sur Exécuter pour voir
Code HTML

<h4 id="browser"></h4>
<table id="results" class="table"></table>

Code JavaScript

function () {

 //准备测试数据, 有200万条数据的大数组
 var testArray = []
  , testObject = {}
  , idx
  , len = 2000000
  , tmp = 0
  , $results = $("#results")
  , $browser = $("#browser")
  ;

 $browser.html(navigator.userAgent);
 $results.html('');

 for (var i = 0; i < len; i++) {
  var number = Math.random(); //若希望加快运算速度可使用取整:Math.random() * 10 | 0
  testArray.push(number);
  testObject[i] = number;
 }

 $results.append('<tr><th>测试代码</th><th>计算结果</th><th>所需时间,毫秒</th></tr>');

 //测试函数
 var test = function(testFunc) {
  var startTime
   , endTime
   , result
   ;

  startTime = new Date();
  tmp = 0;
  testFunc();
  endTime  = new Date();

  //计算测试用例(Test Case)运行所需要的时间
  result = endTime - startTime;
  $results.append('<tr><td><pre class="brush:php;toolbar:false">{0}
{1}{2}'.format(testFunc.toString(), tmp | 0, result)); }; test(function() { //测试for in 的效率 for (idx in testArray) { tmp += testArray[idx]; //经测试,idx是string类型,可能是慢的原因之一 } }); test(function() { //测试for loop循环的效率 for (idx = 0, len = testArray.length; idx < len; idx++) { tmp += testArray[idx]; } }); test(function() { //测试forEach的效率 testArray.forEach(function(data) { tmp += data; }); }); test(function() { //测试不缓存Array.length时效率 for (idx = 0; idx < testArray.length; idx++) { tmp += testArray[idx]; } }); test(function() { //测试使用{} (Object) 存健值对时,使用for in的效率如何 for (idx in testObject) { tmp += testObject[idx]; } }); test(function() { //测试从{} Object查值时的效率如何(这里的健key值事先己知) for (idx = 0, len = testArray.length; idx < len; idx++) { tmp += testObject[idx]; } }); }

Exécuter [Veuillez patienter un instant]
Résultats des tests
Les résultats des tests peuvent varier en fonction du calcul. Ceci est un résumé des résultats des tests de Firefox, Chrome et IE exécutés sur ma machine.

2016313110044207.jpg (971×678)

Voici plusieurs conclusions observées

  • For in est beaucoup plus lent que la boucle for, au moins 20 fois plus lente dans Chrome
  • FF a optimisé forEach (ES5), et ses performances sont meilleures que celles de la boucle for, mais les performances de Chrome/IEn sont médiocres
  • La mise en cache FF/Chrome d'Array.length est un peu plus lente que son utilisation directe. À l'exception de la dernière version d'IE, l'amélioration des performances est minime (c'est très inattendu)
  • Dans certains cas, les performances du moteur JS du FF semblent meilleures que celles du V8
Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn