Ich habe mich gefragt, ob es einen Leistungsunterschied zwischen der Verwendung benannter Funktionen und anonymer Funktionen in Javascript gibt.
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = function() {
// do something
};
}
vs.
function myEventHandler() {
// do something
}
for (var i = 0; i < 1000; ++i) {
myObjects[i].onMyEvent = myEventHandler;
}
Das erste ist aufgeräumter, da es Ihren Code nicht mit selten verwendeten Funktionen überfüllt. Aber ist es wichtig, dass Sie diese Funktion mehrmals neu deklarieren?
Antworten:
Das Leistungsproblem hierbei sind die Kosten für die Erstellung eines neuen Funktionsobjekts bei jeder Iteration der Schleife und nicht die Tatsache, dass Sie eine anonyme Funktion verwenden:
Sie erstellen tausend verschiedene Funktionsobjekte, obwohl sie denselben Code enthalten und nicht an den lexikalischen Bereich gebunden sind ( Abschluss ). Das Folgende scheint andererseits schneller zu sein, da es den Array-Elementen in der gesamten Schleife einfach dieselbe Funktionsreferenz zuweist :
Wenn Sie die anonyme Funktion vor dem Betreten der Schleife erstellen und dann nur innerhalb der Schleife Verweise auf die Array-Elemente zuweisen, werden Sie feststellen, dass es im Vergleich zur benannten Funktionsversion keinerlei Leistung oder semantischen Unterschied gibt:
Kurz gesagt, es gibt keine beobachtbaren Leistungskosten für die Verwendung anonymer überbenannter Funktionen.
Abgesehen davon kann es von oben erscheinen, dass es keinen Unterschied gibt zwischen:
und:
Ersteres ist eine Funktionsdeklaration, während letzteres eine variable Zuordnung zu einer anonymen Funktion ist. Obwohl sie den gleichen Effekt zu haben scheinen, behandelt JavaScript sie etwas anders. Um den Unterschied zu verstehen, empfehle ich, „ Mehrdeutigkeit der JavaScript-Funktionsdeklaration “ zu lesen .
Die tatsächliche Ausführungszeit für jeden Ansatz wird weitgehend von der Implementierung des Compilers und der Laufzeit durch den Browser bestimmt. Einen vollständigen Vergleich der modernen Browserleistung finden Sie auf der JS Perf-Website
quelle
node.js
Webanwendungen besser ist, die Funktionen außerhalb des Anforderungsflusses zu erstellen und als Rückrufe zu übergeben, als anonyme Rückrufe zu erstellen?Hier ist mein Testcode:
Die Ergebnisse:
Test 1: 142 ms Test 2: 1983 ms
Es scheint, dass die JS-Engine nicht erkennt, dass es sich um dieselbe Funktion in Test2 handelt, und sie jedes Mal kompiliert.
quelle
Als allgemeines Entwurfsprinzip sollten Sie vermeiden, denselben Code mehrmals zu implementieren. Stattdessen sollten Sie allgemeinen Code in eine Funktion herausheben und diese (allgemeine, gut getestete, leicht zu ändernde) Funktion von mehreren Stellen aus ausführen.
Wenn Sie (im Gegensatz zu dem, was Sie aus Ihrer Frage ableiten) die interne Funktion einmal deklarieren und diesen Code einmal verwenden (und nichts anderes in Ihrem Programm identisch haben), wird eine anonome Funktion wahrscheinlich (das ist eine Vermutung, Leute) von der genauso behandelt Compiler als normal benannte Funktion.
Es ist eine sehr nützliche Funktion in bestimmten Fällen, sollte aber in vielen Situationen nicht verwendet werden.
quelle
Ich würde keinen großen Unterschied erwarten, aber wenn es einen gibt, wird er wahrscheinlich je nach Skript-Engine oder Browser variieren.
Wenn Sie feststellen, dass der Code leichter zu erfassen ist, ist die Leistung kein Problem, es sei denn, Sie erwarten, dass Sie die Funktion millionenfach aufrufen.
quelle
Anonyme Objekte sind schneller als benannte Objekte. Das Aufrufen von mehr Funktionen ist jedoch teurer und in einem Maße, das die Einsparungen, die Sie durch die Verwendung anonymer Funktionen erzielen könnten, in den Schatten stellt. Jede aufgerufene Funktion wird zum Aufrufstapel hinzugefügt, wodurch ein kleiner, aber nicht trivialer Overhead entsteht.
Aber es sei denn, Sie schreiben Verschlüsselungs- / Entschlüsselungsroutinen oder etwas ähnlich Leistungsempfindliches, wie viele andere angemerkt haben, ist es immer besser, für eleganten, einfach zu lesenden Code gegenüber schnellem Code zu optimieren.
Angenommen, Sie schreiben gut strukturierten Code, sollten Geschwindigkeitsprobleme in der Verantwortung derjenigen liegen, die die Interpreter / Compiler schreiben.
quelle
Wo wir einen Einfluss auf die Leistung haben können, liegt in der Deklaration von Funktionen. Hier ist ein Benchmark für die Deklaration von Funktionen im Kontext einer anderen Funktion oder außerhalb:
http://jsperf.com/function-context-benchmark
In Chrome ist der Vorgang schneller, wenn wir die Funktion außerhalb deklarieren, in Firefox ist es umgekehrt.
In einem anderen Beispiel sehen wir, dass die innere Funktion, wenn sie keine reine Funktion ist, auch in Firefox einen Leistungsmangel aufweist: http://jsperf.com/function-context-benchmark-3
quelle
Was Ihre Schleife in einer Vielzahl von Browsern, insbesondere in IE-Browsern, definitiv schneller macht, ist die folgende Schleife:
Sie haben eine beliebige 1000 in die Schleifenbedingung eingegeben, aber Sie erhalten meine Abweichung, wenn Sie alle Elemente im Array durchgehen möchten.
quelle
Eine Referenz wird fast immer langsamer sein als das, worauf sie sich bezieht. Stellen Sie sich das so vor - nehmen wir an, Sie möchten das Ergebnis der Addition von 1 + 1 drucken. Was sinnvoller ist:
oder
Mir ist klar, dass dies eine sehr vereinfachte Sichtweise ist, aber es ist illustrativ, oder? Verwenden Sie eine Referenz nur, wenn sie mehrmals verwendet werden soll. Welches dieser Beispiele ist beispielsweise sinnvoller:
oder
Die zweite ist eine bessere Übung, auch wenn sie mehr Zeilen enthält. Hoffentlich ist das alles hilfreich. (und die jquery-Syntax hat niemanden abgeschreckt)
quelle
@nickf
(Ich wünschte, ich hätte den Repräsentanten, um nur zu kommentieren, aber ich habe diese Seite gerade erst gefunden.)
Mein Punkt ist, dass hier Verwirrung zwischen benannten / anonymen Funktionen und dem Anwendungsfall des Ausführens + Kompilierens in einer Iteration besteht. Wie ich gezeigt habe, ist der Unterschied zwischen anon + named an sich vernachlässigbar - ich sage, es ist der Anwendungsfall, der fehlerhaft ist.
Es scheint mir offensichtlich, aber wenn nicht, denke ich, ist der beste Rat "mach keine dummen Dinge" (von denen die ständige Blockverschiebung + Objekterstellung dieses Anwendungsfalls eine ist) und wenn du dir nicht sicher bist, teste!
quelle
JA! Anonyme Funktionen sind schneller als normale Funktionen. Wenn Geschwindigkeit von größter Bedeutung ist ... wichtiger als die Wiederverwendung von Code, sollten Sie möglicherweise anonyme Funktionen verwenden.
Hier gibt es einen wirklich guten Artikel über die Optimierung von Javascript und anonymen Funktionen:
http://dev.opera.com/articles/view/efficient-javascript/?page=2
quelle
@nickf
Das ist allerdings ein ziemlich fetter Test. Sie vergleichen dort die Ausführungs- und Kompilierungszeit, die offensichtlich Methode 1 (N-mal kompiliert, abhängig von der JS-Engine) mit Methode 2 (einmal kompilieren) kosten wird. Ich kann mir keinen JS-Entwickler vorstellen, der seine Probezeit so schreiben würde.
Ein weitaus realistischerer Ansatz ist die anonyme Zuweisung, da Sie sie tatsächlich für Ihr Dokument verwenden. Die onclick-Methode ähnelt eher der folgenden, was die anon-Methode in der Tat leicht begünstigt.
Verwenden eines ähnlichen Testframeworks wie Ihres:
quelle
Wie in den Kommentaren zu @nickf Antwort darauf hingewiesen: Die Antwort auf
ist einfach ja. Aber wie sein JS Perf zeigt, ist es nicht um den Faktor eine Million langsamer, was zeigt, dass es mit der Zeit tatsächlich schneller wird.
Die interessantere Frage für mich ist:
Wenn eine Funktion eine komplexe Berechnung durchführt, ist die Zeit zum Erstellen des Funktionsobjekts höchstwahrscheinlich vernachlässigbar. Aber was ist mit dem Overhead von create in Fällen , in denen der Lauf schnell ist? Zum Beispiel:
Diese JS Perf zeigt, dass das einmalige Erstellen der Funktion erwartungsgemäß schneller ist. Selbst bei einem sehr schnellen Vorgang wie einem einfachen Hinzufügen beträgt der Aufwand für das wiederholte Erstellen der Funktion nur wenige Prozent.
Der Unterschied wird wahrscheinlich nur in Fällen signifikant, in denen das Erstellen des Funktionsobjekts komplex ist, während eine vernachlässigbare Laufzeit beibehalten wird, z. B. wenn der gesamte Funktionskörper in eine eingeschlossen ist
if (unlikelyCondition) { ... }
.quelle