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';
}
};
})();
Und die schnellere Funktion: (Beachten Sie, dass immer wieder die gleichen Variablen kb / mb / gb berechnet werden müssen). Wo gewinnt es Leistung?
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';
}
};
javascript
performance
Zu meinem
quelle
quelle
Antworten:
Moderne JavaScript-Engines kompilieren allesamt just-in-time. Man kann keine Vermutungen darüber anstellen, was es "immer und immer wieder schaffen muss". Diese Art der Berechnung ist in beiden Fällen relativ einfach zu optimieren.
Andererseits ist das Schließen über konstante Variablen kein typischer Fall, für den Sie die JIT-Kompilierung anstreben würden. In der Regel erstellen Sie einen Abschluss, wenn Sie diese Variablen bei verschiedenen Aufrufen ändern möchten. Sie erstellen auch eine zusätzliche Zeiger-Dereferenzierung, um auf diese Variablen zuzugreifen, z. B. den Unterschied zwischen dem Zugriff auf eine Mitgliedsvariable und ein lokales int in OOP.
Diese Art von Situation ist der Grund, warum die Leute die Linie "vorzeitige Optimierung" streichen. Die einfachen Optimierungen werden bereits vom Compiler durchgeführt.
quelle
Variablen sind billig. Ausführungskontexte und Umfangsketten sind teuer.
Es gibt verschiedene Antworten, die im Wesentlichen auf "weil Abschlüsse" hinauslaufen, und diese sind im Wesentlichen wahr, aber das Problem betrifft nicht speziell den Abschluss, sondern die Tatsache, dass Sie eine Funktion haben, die auf Variablen in einem anderen Bereich verweist. Sie hätten das gleiche Problem, wenn dies globale Variablen auf dem wären
window
Objekt , im Gegensatz zu lokalen Variablen innerhalb des IIFE. Probieren Sie es aus und sehen Sie.Also in Ihrer ersten Funktion, wenn die Engine diese Anweisung sieht:
Es müssen folgende Schritte ausgeführt werden:
size
im aktuellen Bereich. (Fand es.)GB
im aktuellen Bereich. (Nicht gefunden.)GB
im übergeordneten Bereich nach einer Variablen . (Fand es.)gbSize
.Schritt 3 ist erheblich teurer als nur die Zuweisung einer Variablen. Darüber hinaus tun Sie dies fünfmal , einschließlich zweimal für beide
GB
undMB
. Ich vermute, dass, wenn Sie diese zu Beginn der Funktion Alias (zvar gb = GB
) und stattdessen auf den Alias verweisen, dies tatsächlich zu einer geringen Beschleunigung führt, obwohl es auch möglich ist, dass einige JS-Engines diese Optimierung bereits durchführen. Und der effektivste Weg, die Ausführung zu beschleunigen, besteht natürlich darin, die Scope-Kette überhaupt nicht zu durchlaufen.Beachten Sie, dass JavaScript nicht wie eine kompilierte, statisch typisierte Sprache ist, in der der Compiler diese variablen Adressen zur Kompilierungszeit auflöst. Die JS-Engine muss sie nach Namen auflösen , und diese Suchvorgänge werden jedes Mal zur Laufzeit ausgeführt. Sie sollten sie daher nach Möglichkeit meiden.
Die variable Zuweisung ist in JavaScript extrem günstig. Es könnte tatsächlich die billigste Operation sein, obwohl ich nichts habe, um diese Aussage zu stützen. Trotzdem kann man mit Sicherheit sagen, dass es fast nie eine gute Idee ist, das Erstellen von Variablen zu vermeiden . Fast jede Optimierung, die Sie in diesem Bereich vornehmen, wird die Leistung sogar noch verschlechtern.
quelle
var a, b, c
wir auf sie zugreifen könnenb
alsscope[1]
. Alle Bereiche sind nummeriert. Wenn dieser Bereich fünf Bereiche tief verschachtelt ist,b
wird er vollständig angesprochen,env[5][1]
was beim Parsen bekannt ist. Im nativen Code entsprechen Bereiche Stapelsegmenten. Verschlüsse sind etwas komplizierter, da sie denenv
*(scope->outer + variable_offset)
für einen Zugriff erhalten; Jede zusätzliche Funktionsumfangsebene kostet eine zusätzliche Zeiger-Dereferenzierung. Scheint, wir hatten beide recht :)Bei einem Beispiel handelt es sich um eine Schließung, bei dem anderen nicht. Das Implementieren von Closures ist etwas knifflig, da Closed-Over-Variablen nicht wie normale Variablen funktionieren. Dies ist in einer einfachen Sprache wie C offensichtlicher, aber ich werde JavaScript verwenden, um dies zu veranschaulichen.
Ein Closure besteht nicht nur aus einer Funktion, sondern auch aus allen Variablen, über die es geschlossen hat. Wenn wir diese Funktion aufrufen möchten, müssen wir auch alle Variablen bereitstellen, die geschlossen sind. Wir können einen Abschluss durch eine Funktion modellieren, die ein Objekt als erstes Argument empfängt, das diese über Variablen geschlossenen Werte darstellt:
Beachten Sie die
closure.apply(closure, ...realArgs)
dazu erforderliche umständliche AufrufkonventionDie integrierte Objektunterstützung von JavaScript ermöglicht es, das explizite
vars
Argument wegzulassen undthis
stattdessen Folgendes zu verwenden :Diese Beispiele entsprechen dem Code, der tatsächlich Abschlüsse verwendet:
In diesem letzten Beispiel wird das Objekt nur zum Gruppieren der beiden zurückgegebenen Funktionen verwendet. Die
this
Bindung ist irrelevant. Alle Details zur Ermöglichung von Schließungen - die Übergabe versteckter Daten an die eigentliche Funktion, die Änderung aller Zugriffe auf Schließungsvariablen, um in diesen versteckten Daten nachzuschlagen - werden von der Sprache erledigt.Das Aufrufen von Closures bedeutet jedoch den Mehraufwand für das Übergeben dieser zusätzlichen Daten, und das Ausführen eines Closures bedeutet den Mehraufwand für das Nachschlagen dieser zusätzlichen Daten - der durch eine schlechte Cache-Lokalität und normalerweise eine Zeiger-Dereferenzierung im Vergleich zu normalen Variablen verschlechtert wird -, so dass dies nicht verwunderlich ist Eine Lösung, die nicht auf Verschlüssen beruht, bietet eine bessere Leistung. Zumal alles, was Sie mit Ihrem Verschluss ersparen, ein paar extrem kostengünstige Rechenoperationen sind, die beim Parsen sogar konstant gefaltet werden können.
quelle