Est-ce que les JIT de JavaScript modernes ont besoin d'une mise en cache de longueur de matrice dans les boucles?

Je trouve la pratique de la mise en cache d'une propriété de length de tableau dans une boucle for assez désagréable. Comme dans,

 for (var i = 0, l = myArray.length; i < l; ++i) { // ... } 

Dans mes yeux au moins, cela nuit beaucoup à la lisibilité par rapport au simple

 for (var i = 0; i < myArray.length; ++i) { // ... } 

(Sans oublier qu'il fuit une autre variable dans la fonction environnante en raison de la nature de la portée lexique et du levage).

Je voudrais pouvoir dire à tous ceux qui le font "ne vous embêtez pas", les JIT JIT modernes optimisent ce tour. " De toute évidence, ce n'est pas une optimisation banale, puisque vous pourriez, par exemple, modifier le tableau pendant qu'il se déroule, mais je pense que, compte tenu de toutes les choses folles que j'ai entendues sur les JITers et leurs astuces d'analyse d'exécution, ils en seraient parvenus à présent.

Quelqu'un a-t-il des preuves d'une manière ou d'une autre?

Et oui, je souhaite aussi qu'il suffise de dire "c'est une micro-optimisation, ne faites pas cela jusqu'à ce que vous soyez de profil". Mais tout le monde n'écoute pas ce genre de raison, surtout quand il devient habituel de cacher la longueur et ils finissent par le faire automatiquement, presque comme un choix de style.

Cela dépend de quelques éléments:

  • Que vous ayez prouvé que votre code passe beaucoup de temps en boucle
  • Que le navigateur le plus lent que vous bénéficiez pleinement bénéficie de la mise en cache de la longueur du tableau
  • Que vous ou les personnes qui travaillent sur votre code trouvent la mise en cache de la longueur du tableau difficile à lire

Il semble que, par rapport aux benchmarks que j'ai vus (par exemple, ici et ici ), les performances dans IE <9 (qui seront généralement les navigateurs les plus lents que vous devez gérer) bénéficient de la mise en cache de la longueur du tableau, donc il est intéressant de le faire . Pour ce qu'il vaut, j'ai une longue habitude de mettre en cache la longueur du tableau et, par conséquent, il est facile de lire. Il existe également d'autres optimisations de boucle qui peuvent avoir un effet, comme le comptage vers le bas plutôt que vers le haut.

Voici une discussion pertinente à ce sujet dans la liste de diffusion de JSMentors: http://groups.google.com/group/jsmentors/browse_thread/thread/526c1ddeccfe90f0

Mes tests montrent que tous les principaux navigateurs plus récents cachent la propriété length des tableaux. Vous n'avez pas besoin de le mettre en cache vous-même, sauf si vous êtes préoccupé par IE6 ou 7, je ne me souviens pas exactement. Cependant, j'ai utilisé un autre style d'itération depuis ces jours car cela me donne un autre avantage que je vais décrire dans l'exemple suivant:

 var arr = ["Hello", "there", "sup"]; for (var i=0, str; str = arr[i]; i++) { // I already have the item being iterated in the loop as 'str' alert(str); } 

Vous devez vous rendre compte que ce style d'itération s'arrête si le tableau est autorisé à contenir des valeurs "fausses", donc ce style ne peut être utilisé dans ce cas.

Tout d'abord, comment est-ce plus difficile à faire ou moins lisible?

 var i = someArray.length; while(i--){ //doStuff to someArray[i] } 

Ce n'est pas une micro-optimisation cryptique étrange. C'est simplement un principe fondamental d'évitement du travail. Ne pas utiliser le '.' Ou '[]' plus que nécessaire devrait être aussi évident que de ne pas recalculer pi plus d'une fois (en supposant que vous ne saviez pas que nous l'avons déjà dans l'objet Math).

[Éléments rancards yoke]

Si someArray est entièrement interne à une fonction, c'est un jeu équitable pour l'optimisation JIT de sa propriété length qui ressemble vraiment à un getter qui comptabilise les éléments du tableau chaque fois que vous y accédez. Un JIT a pu voir qu'il était entièrement localisé et ignorer le comportement de comptage réel.

Mais cela implique une grande complexité. Chaque fois que vous faites quoi que ce soit qui modifie ce tableau, vous devez traiter la longueur comme une propriété statique et indiquer à votre tableau des méthodes de modification (le code de code natif de celles-ci, je veux dire) pour définir la propriété manuellement alors que la longueur normale ne compte que les éléments chaque fois qu'il est Référencé. Cela signifie que chaque fois qu'une nouvelle méthode de modification de tableau est ajoutée, vous devez mettre à jour le JIT pour dériver le comportement pour les références de longueur d'un tableau à portée locale.

Je pourrais voir Chrome faire cela finalement, mais je ne pense pas qu'il soit encore basé sur des tests vraiment informels. Je ne suis pas sûr que IE ait toujours ce niveau de performance en accordant une priorité. En ce qui concerne les autres navigateurs, vous pourriez faire un argument fort pour le problème de maintenance consistant à avoir un comportement de dérivation pour chaque nouvelle méthode de tableau étant plus difficile que sa valeur. À tout le moins, ce ne serait pas la priorité absolue.

En fin de compte, accéder à la propriété length chaque cycle de boucle ne vous coûtera pas une tonne même dans les anciens navigateurs pour une boucle JS typique. Mais je conseillerais d'avoir l'habitude de mettre en cache toute recherche de propriété effectuée plus d'une fois, car avec les propriétés de getter, vous ne pouvez jamais être sûr de combien de travail est fait, quel navigateur optimise-t-il de quelle manière ou quel type de performance vous coûte? La route lorsque quelqu'un décide de déplacer someArray en dehors de la fonction, ce qui pourrait conduire à la vérification de l'objet d'appel dans une douzaine d'endroits avant de trouver ce qu'il cherche à chaque fois que vous accédez à cet accès.

Cacher les recherches de propriétés et les retours de méthode est facile, nettoie votre code et finalement le rend plus souple et plus performant face à la modification. Même si un ou deux JIT ont rendu cela inutile dans des circonstances impliquant un certain nombre de «ifs», vous ne pourriez pas être certain qu'ils le feraient toujours ou que votre code continuerait à le rendre possible.

Donc oui, excusez-moi pour le anti-let-the-compiler-handle-it rant mais je ne vois pas pourquoi vous voudrez jamais ne pas mettre en cache vos propriétés. C'est facile. C'est propre. Il garantit de meilleures performances indépendamment du navigateur ou du mouvement de l'objet ayant sa propriété examinée dans un champ extérieur.

Mais il me fait vraiment pisser que Word Word se charge aussi lentement maintenant qu'ils l'ont fait en 1995 et que les gens continuent à écrire des sites java horribles et à faible performance même si la VM de Java supposée bat tous les concurrents non compilés pour la performance. Je pense que cette idée que vous pouvez laisser le compilateur trier les détails de performance et que «les ordinateurs modernes sont si rapides» a beaucoup à voir avec cela. Nous devons toujours être conscients de l'évitement du travail, lorsque le travail est facile à éviter et ne menace pas la lisibilité / la maintenabilité, l'OMI. Le faire différemment ne m'a jamais aidé (ou je soupçonne quiconque) d'écrire le code plus rapidement à long terme.