var toSizeString = (function() {
var KB = 1024.0,
MB = 1024 * KB,
GB = 1024 * MB;
return function(size) {
var gbSize = size / GB,
gbMod = size % GB,
mbSize = gbMod / MB,
mbMod = gbMod % MB,
kbSize = mbMod / KB;
if (Math.floor(gbSize)) {
return gbSize.toFixed(1) + 'GB';
} else if (Math.floor(mbSize)) {
return mbSize.toFixed(1) + 'MB';
} else if (Math.floor(kbSize)) {
return kbSize.toFixed(1) + 'KB';
} else {
return size + 'B';
}
};
})();
Et la fonction plus rapide: (notez qu'il doit toujours calculer les mêmes variables kb / mb / gb encore et encore). Où gagne-t-il des performances?
function toSizeString (size) {
var KB = 1024.0,
MB = 1024 * KB,
GB = 1024 * MB;
var gbSize = size / GB,
gbMod = size % GB,
mbSize = gbMod / MB,
mbMod = gbMod % MB,
kbSize = mbMod / KB;
if (Math.floor(gbSize)) {
return gbSize.toFixed(1) + 'GB';
} else if (Math.floor(mbSize)) {
return mbSize.toFixed(1) + 'MB';
} else if (Math.floor(kbSize)) {
return kbSize.toFixed(1) + 'KB';
} else {
return size + 'B';
}
};
Réponses:
Les moteurs JavaScript modernes effectuent tous une compilation juste à temps. Vous ne pouvez pas faire de présomptions sur ce qu'il "doit créer encore et encore". Ce type de calcul est relativement facile à optimiser, dans les deux cas.
D'un autre côté, la fermeture de variables constantes n'est pas un cas typique pour lequel vous viseriez une compilation JIT. Vous créez généralement une fermeture lorsque vous souhaitez pouvoir modifier ces variables à différentes invocations. Vous créez également une déréférence de pointeur supplémentaire pour accéder à ces variables, comme la différence entre l'accès à une variable membre et un int local dans la POO.
Ce genre de situation explique pourquoi les gens abandonnent la ligne «optimisation prématurée». Les optimisations faciles sont déjà effectuées par le compilateur.
la source
Les variables sont bon marché. Les contextes d'exécution et les chaînes de portée sont coûteux.
Il existe différentes réponses qui se résument essentiellement à "parce que les fermetures", et celles-ci sont essentiellement vraies, mais le problème n'est pas spécifiquement avec la fermeture, c'est le fait que vous avez une fonction référençant des variables dans une portée différente. Vous auriez le même problème s'il s'agissait de variables globales sur l'
window
objet, par opposition aux variables locales à l'intérieur de l'IIFE. Essayez-le et voyez.Donc, dans votre première fonction, lorsque le moteur voit cette déclaration:
Il doit prendre les mesures suivantes:
size
dans la portée actuelle. (Je l'ai trouvé.)GB
dans la portée actuelle. (Pas trouvé.)GB
dans la portée parent. (Je l'ai trouvé.)gbSize
.L'étape 3 est considérablement plus coûteuse que la simple allocation d'une variable. De plus, vous faites cela cinq fois , dont deux fois pour
GB
etMB
. Je soupçonne que si vous les aliasiez au début de la fonction (par exemplevar gb = GB
) et référençiez l'alias à la place, cela produirait en fait une petite accélération, bien qu'il soit également possible que certains moteurs JS effectuent déjà cette optimisation. Et bien sûr, le moyen le plus efficace d'accélérer l'exécution est tout simplement de ne pas traverser du tout la chaîne de portée.Gardez à l'esprit que JavaScript n'est pas comme un langage compilé de type statique où le compilateur résout ces adresses de variables au moment de la compilation. Le moteur JS doit les résoudre par leur nom , et ces recherches se produisent au moment de l'exécution, à chaque fois. Vous devez donc les éviter lorsque cela est possible.
L'affectation de variables est extrêmement bon marché en JavaScript. Ce pourrait en fait être l'opération la moins chère, bien que je n'aie rien pour étayer cette affirmation. Néanmoins, il est sûr de dire que ce n'est presque jamais une bonne idée d'essayer d' éviter de créer des variables; presque toute optimisation que vous essayez de faire dans ce domaine finira par empirer les choses, en termes de performances.
la source
var a, b, c
nous pouvons accéder enb
tant quescope[1]
. Toutes les étendues sont numérotées, et si cette étendue est imbriquée à cinq étendues de profondeur, elleb
est entièrement traitée parenv[5][1]
ce qui est connu lors de l'analyse. Dans le code natif, les étendues correspondent aux segments de pile. Les fermetures sont plus compliquées car elles doivent sauvegarder et remplacer leenv
*(scope->outer + variable_offset)
pour un accès; chaque niveau de portée de fonction supplémentaire coûte une déréférence de pointeur supplémentaire. Semble nous étions tous deux à droite :)Un exemple implique une fermeture, l'autre non. La mise en œuvre des fermetures est un peu délicate, car les variables fermées ne fonctionnent pas comme les variables normales. C'est plus évident dans un langage de bas niveau comme C, mais je vais utiliser JavaScript pour illustrer cela.
Une fermeture ne consiste pas seulement en une fonction, mais aussi en toutes les variables qu'elle a fermées. Lorsque nous voulons invoquer cette fonction, nous devons également fournir toutes les variables fermées. Nous pouvons modéliser une fermeture par une fonction qui reçoit un objet comme premier argument qui représente ces variables fermées:
Notez la convention d'appel maladroite que
closure.apply(closure, ...realArgs)
cela nécessiteLa prise en charge des objets intégrés de JavaScript permet d'omettre l'
vars
argument explicite et nous permet d'utiliser à lathis
place:Ces exemples sont équivalents à ce code utilisant des fermetures:
Dans ce dernier exemple, l'objet n'est utilisé que pour regrouper les deux fonctions retournées; le
this
liaison n'est pas pertinente. Tous les détails pour rendre les fermetures possibles - passer des données cachées à la fonction réelle, changer tous les accès aux variables de fermeture en recherches dans ces données cachées - sont pris en charge par le langage.Mais appeler des fermetures implique la surcharge de la transmission de ces données supplémentaires, et l'exécution d'une fermeture implique la surcharge de recherches dans ces données supplémentaires - aggravées par une mauvaise localité de cache et généralement une déréférence de pointeur par rapport aux variables ordinaires - de sorte qu'il n'est pas surprenant que une solution qui ne repose pas sur des fermetures fonctionne mieux. D'autant plus que tout ce que votre fermeture vous permet d'économiser est quelques opérations arithmétiques extrêmement bon marché, qui pourraient même être pliées en permanence pendant l'analyse.
la source