Indépendamment des différences fonctionnelles, l'utilisation des nouveaux mots-clés «let» et «const» a-t-elle un impact généralisé ou spécifique sur les performances par rapport à «var»?
Après avoir exécuté le programme:
function timeit(f, N, S) {
var start, timeTaken;
var stats = {min: 1e50, max: 0, N: 0, sum: 0, sqsum: 0};
var i;
for (i = 0; i < S; ++i) {
start = Date.now();
f(N);
timeTaken = Date.now() - start;
stats.min = Math.min(timeTaken, stats.min);
stats.max = Math.max(timeTaken, stats.max);
stats.sum += timeTaken;
stats.sqsum += timeTaken * timeTaken;
stats.N++
}
var mean = stats.sum / stats.N;
var sqmean = stats.sqsum / stats.N;
return {min: stats.min, max: stats.max, mean: mean, spread: Math.sqrt(sqmean - mean * mean)};
}
var variable1 = 10;
var variable2 = 10;
var variable3 = 10;
var variable4 = 10;
var variable5 = 10;
var variable6 = 10;
var variable7 = 10;
var variable8 = 10;
var variable9 = 10;
var variable10 = 10;
function varAccess(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += variable1;
sum += variable2;
sum += variable3;
sum += variable4;
sum += variable5;
sum += variable6;
sum += variable7;
sum += variable8;
sum += variable9;
sum += variable10;
}
return sum;
}
const constant1 = 10;
const constant2 = 10;
const constant3 = 10;
const constant4 = 10;
const constant5 = 10;
const constant6 = 10;
const constant7 = 10;
const constant8 = 10;
const constant9 = 10;
const constant10 = 10;
function constAccess(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += constant1;
sum += constant2;
sum += constant3;
sum += constant4;
sum += constant5;
sum += constant6;
sum += constant7;
sum += constant8;
sum += constant9;
sum += constant10;
}
return sum;
}
function control(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
}
return sum;
}
console.log("ctl = " + JSON.stringify(timeit(control, 10000000, 50)));
console.log("con = " + JSON.stringify(timeit(constAccess, 10000000, 50)));
console.log("var = " + JSON.stringify(timeit(varAccess, 10000000, 50)));
.. Mes résultats sont les suivants:
ctl = {"min":101,"max":117,"mean":108.34,"spread":4.145407097016924}
con = {"min":107,"max":572,"mean":435.7,"spread":169.4998820058587}
var = {"min":103,"max":608,"mean":439.82,"spread":176.44417700791374}
Cependant, la discussion comme indiqué ici semble indiquer un réel potentiel de différences de performance dans certains scénarios: https://esdiscuss.org/topic/performance-concern-with-let-const
javascript
performance
constants
v8
let
sean2078
la source
la source
let
utilisé dans la portée de bloc devrait être plus performant quevar
, qui n'a pas de portée de bloc, mais seulement une portée de fonction.let
ferait, puis le ramasse-miettes, tandis quevar
, qui est à portée de fonction, ne fonctionnerait pas nécessairement de la même manière. Encore une fois, je pense que c'est tellement spécifique à l'utilisation, que les deuxlet
etconst
peuvent être plus performants, mais ne le seront pas toujours.var
etlet
: il n'utilise jamaislet
du tout.Réponses:
TL; DR
En théorie , une version non optimisée de cette boucle:
for (let i = 0; i < 500; ++i) { doSomethingWith(i); }
peut être plus lent qu'une version non optimisée de la même boucle avec
var
:for (var i = 0; i < 500; ++i) { doSomethingWith(i); }
car une variable différente
i
est créée pour chaque itération de boucle aveclet
, alors qu'il n'y en a qu'une seulei
avecvar
.Contre cela, c'est le fait que le
var
est hissé, donc il est déclaré en dehors de la boucle alors que lelet
n'est déclaré que dans la boucle, ce qui peut offrir un avantage d'optimisation.En pratique , ici en 2018, les moteurs JavaScript modernes font suffisamment d'introspection de la boucle pour savoir quand ils peuvent optimiser cette différence. (Même avant, il y a de fortes chances que votre boucle fasse suffisamment de travail pour que les
let
frais généraux supplémentaires soient supprimés de toute façon. Mais maintenant, vous n'avez même plus à vous en soucier.)Méfiez-vous des benchmarks synthétiques car ils sont extrêmement faciles à se tromper et déclenchent les optimiseurs de moteur JavaScript d'une manière que le vrai code ne fait pas (à la fois bonne et mauvaise). Cependant, si vous voulez un benchmark synthétique, en voici un:
Afficher l'extrait de code
const now = typeof performance === "object" && performance.now ? performance.now.bind(performance) : Date.now.bind(Date); const btn = document.getElementById("btn"); btn.addEventListener("click", function() { btn.disabled = true; runTest(); }); const maxTests = 100; const loopLimit = 50000000; const expectedX = 1249999975000000; function runTest(index = 1, results = {usingVar: 0, usingLet: 0}) { console.log(`Running Test #${index} of ${maxTests}`); setTimeout(() => { const varTime = usingVar(); const letTime = usingLet(); results.usingVar += varTime; results.usingLet += letTime; console.log(`Test ${index}: var = ${varTime}ms, let = ${letTime}ms`); ++index; if (index <= maxTests) { setTimeout(() => runTest(index, results), 0); } else { console.log(`Average time with var: ${(results.usingVar / maxTests).toFixed(2)}ms`); console.log(`Average time with let: ${(results.usingLet / maxTests).toFixed(2)}ms`); btn.disabled = false; } }, 0); } function usingVar() { const start = now(); let x = 0; for (var i = 0; i < loopLimit; i++) { x += i; } if (x !== expectedX) { throw new Error("Error in test"); } return now() - start; } function usingLet() { const start = now(); let x = 0; for (let i = 0; i < loopLimit; i++) { x += i; } if (x !== expectedX) { throw new Error("Error in test"); } return now() - start; }
<input id="btn" type="button" value="Start">
Il dit qu'il n'y a pas de différence significative dans ce test synthétique sur V8 / Chrome ou SpiderMonkey / Firefox. (Les tests répétés dans les deux navigateurs ont l'un gagnant, ou l'autre gagnant, et dans les deux cas dans une marge d'erreur.) Mais encore une fois, c'est une référence synthétique, pas votre code. Souciez-vous des performances de votre code quand et si votre code a un problème de performances.
En ce qui concerne le style, je préfère
let
pour l'avantage de la portée et l'avantage de la fermeture dans les boucles si j'utilise la variable de boucle dans une fermeture.Détails
La différence importante entre
var
etlet
dans unefor
boucle est qu'un différenti
est créé pour chaque itération; il résout le problème classique des "fermetures en boucle":Afficher l'extrait de code
function usingVar() { for (var i = 0; i < 3; ++i) { setTimeout(function() { console.log("var's i: " + i); }, 0); } } function usingLet() { for (let i = 0; i < 3; ++i) { setTimeout(function() { console.log("let's i: " + i); }, 0); } } usingVar(); setTimeout(usingLet, 20);
Créer le nouvel EnvironmentRecord pour chaque corps de boucle ( lien de spécification ) est un travail, et le travail prend du temps, c'est pourquoi en théorie la
let
version est plus lente que lavar
version.Mais la différence n'a d'importance que si vous créez une fonction (fermeture) dans la boucle qui utilise
i
, comme je l'ai fait dans cet exemple d'extrait de code exécutable ci-dessus. Sinon, la distinction ne peut pas être observée et peut être optimisée.Ici en 2018, il semble que V8 (et SpiderMonkey dans Firefox) fasse une introspection suffisante pour qu'il n'y ait aucun coût de performance dans une boucle qui n'utilise pas la
let
sémantique de variable par itération de. Voir ce test .Dans certains cas, cela
const
pourrait bien offrir une opportunité d'optimisation quivar
ne le serait pas, en particulier pour les variables globales.Le problème avec une variable globale est qu'elle est, eh bien, globale; n'importe quel code n'importe où pourrait y accéder. Donc, si vous déclarez une variable avec
var
laquelle vous n'avez jamais l'intention de changer (et ne changez jamais votre code), le moteur ne peut pas supposer qu'elle ne changera jamais à la suite d'un code chargé plus tard ou similaire.Avec
const
, cependant, vous dites explicitement au moteur que la valeur ne peut pas changer¹. Il est donc libre de faire toute optimisation qu'il souhaite, y compris d'émettre un littéral au lieu d'une référence de variable au code qui l'utilise, sachant que les valeurs ne peuvent pas être modifiées.¹ N'oubliez pas qu'avec les objets, la valeur est une référence à l'objet, pas à l'objet lui-même. Donc avec
const o = {}
, vous pouvez changer l'état de l'objet (o.answer = 42
), mais vous ne pouvez paso
pointer vers un nouvel objet (car cela nécessiterait de changer la référence d'objet qu'il contient).Lors de l'utilisation
let
ouconst
dans d'autresvar
situations similaires, il est peu probable qu'ils aient des performances différentes. Cette fonction doit avoir exactement les mêmes performances que vous utilisiezvar
oulet
, par exemple:function foo() { var i = 0; while (Math.random() < 0.5) { ++i; } return i; }
Tout cela, bien sûr, n'a pas d'importance et quelque chose à craindre uniquement si et quand il y a un vrai problème à résoudre.
la source
let
dans l'exemple de boucle. La différence de performances ne vaut tout simplement pas la peine de s'en inquiéter dans le cas de 99,999%."LET" EST MIEUX DANS LES DÉCLARATIONS DE BOUCLE
Avec un simple test (5 fois) dans le navigateur comme ça:
// WITH VAR console.time("var-time") for(var i = 0; i < 500000; i++){} console.timeEnd("var-time")
Le temps moyen d'exécution est supérieur à 2,5 ms
// WITH LET console.time("let-time") for(let i = 0; i < 500000; i++){} console.timeEnd("let-time")
Le temps moyen d'exécution est supérieur à 1,5 ms
J'ai trouvé que le temps de boucle avec let est meilleur.
la source
var=138.8ms
etlet=4ms
. Ce n'est pas une faute de frappe,let
c'est plus de 30 fois plus rapide en ce momentvar=2.6ms
etlet=1.0ms
. Alors laissez entrer Node est un peu plus de deux fois plus rapide.La réponse de TJ Crowder est tellement excellente.
Voici un ajout de: "Quand en aurais-je le plus pour mon argent en éditant les déclarations var existantes dans const?"
J'ai trouvé que la plus grande amélioration des performances était liée aux fonctions "exportées".
Donc, si les fichiers A, B, R et Z font appel à une fonction "utilitaire" dans le fichier U qui est couramment utilisée via votre application, alors basculer cette fonction utilitaire sur "const" et la référence du fichier parent à un const peut eak des performances améliorées. Il me semblait que ce n'était pas beaucoup plus rapide, mais la consommation globale de mémoire a été réduite d'environ 1 à 3% pour mon application Frankenstein-ed grossièrement monolithique. Ce qui, si vous dépensez des sacs d'argent sur le cloud ou votre serveur baremetal, pourrait être une bonne raison de passer 30 minutes à parcourir et mettre à jour certaines de ces déclarations var vers const.
Je me rends compte que si vous lisez comment const, var, et laissez travailler sous les couvertures, vous avez probablement déjà conclu ce qui précède ... mais au cas où vous auriez "jeté un coup d'œil" dessus: D.
D'après ce que je me souviens de l'analyse comparative sur le nœud v8.12.0 lorsque je faisais la mise à jour, mon application est passée d'une consommation inactive d'environ 240 Mo de RAM à ~ 233 Mo de RAM.
la source
La réponse de TJ Crowder est très bonne mais:
L'effet de l'écart de performance entre var et let peut être vu dans un programme complet réel et non sur une seule boucle de base.
Quoi qu'il en soit, utiliser let là où vous n'êtes pas obligé de rendre votre code moins lisible.
la source