Frage

Ich habe mich gefragt, gibt es einen Unterschied in der Leistung zwischen benannten Funktionen und anonyme Funktionen in Javascript?

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;
}

Die erste ist aufgeräumter, da es nicht, Ihren Code nicht vollstopfen mit selten verwendete Funktionen, aber tut es eine Rolle, dass Sie wieder zu erklären, dass die Funktion mehrmals?

War es hilfreich?

Lösung

Die Performance Problem hierbei ist, die Kosten für ein neues Funktionsobjekt bei jeder Iteration der Schleife zu schaffen, und nicht die Tatsache, dass Sie eine anonyme Funktion verwenden:

for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = function() {
        // do something    
    };
}

Sie erstellen tausend verschiedene Funktionsobjekte, auch wenn sie den gleichen Körper des Codes und keine Bindung an den lexikalischen Gültigkeitsbereich ( Schließung ). Die folgende scheint schneller, auf der anderen Seite, weil es einfach so tritt die gleicher Funktion Bezug auf die Array-Elemente in der Schleife:

function myEventHandler() {
    // do something
}

for (var i = 0; i < 1000; ++i) {
    myObjects[i].onMyEvent = myEventHandler;
}

Wenn Sie die anonyme Funktion erstellen sind, bevor die Schleife eintritt, dann nur Verweise darauf zuweisen zu den Array-Elementen, während innerhalb der Schleife, werden Sie feststellen, dass es keine Leistung oder semantischer whatsoever Unterschied, wenn zu der benannten Funktion Version verglichen :

var handler = function() {
    // do something    
};
for (var i = 0; i < 1000; ++i) {    
    myObjects[i].onMyEvent = handler;
}

Kurz gesagt, gibt es keine beobachtbare Leistungskosten zur Verwendung von anonymen über genannte Funktionen.

Als Nebenwirkung kann es von oben erscheinen, dass es keinen Unterschied zwischen:

function myEventHandler() { /* ... */ }

und

var myEventHandler = function() { /* ... */ }

Das erstere ist eine Funktionsdeklaration , während die letztere eine variable Zuordnung zu einer anonymen Funktion ist. Obwohl sie die gleiche Wirkung zu haben scheinen mag, tut JavaScript behandeln sie etwas anders. Um den Unterschied zu verstehen, empfehle ich das Lesen, „ JavaScript-Funktion Erklärung Mehrdeutigkeit “.

Die tatsächliche Ausführungszeit für jeden Ansatz wird weitgehend durch den Browser-Implementierung des Compilers und Laufzeit diktiert werden. Für einen vollständigen Vergleich der modernen Browser-Leistung, besuchen Sie die JS-Perf-Website

Andere Tipps

Hier ist mein Test-Code:

var dummyVar;
function test1() {
    for (var i = 0; i < 1000000; ++i) {
        dummyVar = myFunc;
    }
}

function test2() {
    for (var i = 0; i < 1000000; ++i) {
        dummyVar = function() {
            var x = 0;
            x++;
        };
    }
}

function myFunc() {
    var x = 0;
    x++;
}

document.onclick = function() {
    var start = new Date();
    test1();
    var mid = new Date();
    test2();
    var end = new Date();
    alert ("Test 1: " + (mid - start) + "\n Test 2: " + (end - mid));
}

Die Ergebnisse:
Test 1: 142ms Test 2: 1983ms

Es scheint, dass die JS-Engine erkennt nicht, dass es die gleiche Funktion in Test2 ist und kompiliert es jedes Mal.

Als allgemeines Konstruktionsprinzip, sollten Sie vermeiden, dass die gleichen Code mehrfach implimenting. Stattdessen sollten Sie gemeinsamen Code ausheben in eine Funktion und ausführen, die (allgemeine, gut getestet, einfach zu ändern) Funktion von mehreren Stellen.

Wenn (im Gegensatz zu, was Sie aus Ihrer Frage ableiten) die interne Funktion einmal deklarieren und diesen Code einmal mit (und nichts anderes identisch in Ihrem Programm haben), dann eine anonomous Funktion wahrscheinlich (das ist ein wird auf die gleiche Weise durch den Compiler als eine normale Funktion namens behandelt erraten Leute).

Es ist eine sehr nützliche Funktion in bestimmten Fällen, soll aber nicht in vielen Situationen verwendet werden.

Ich würde nicht viel Unterschied erwarten, aber wenn es eine ist, wird es wahrscheinlich durch Scripting-Engine oder Browser variieren.

Wenn Sie den Code leichter grok finden, ist die Leistung ein Nicht-Thema, wenn Sie erwarten, dass die Funktion millionenfach nennen.

Anonyme Objekte sind schneller als benannte Objekte. Aber mehr Funktionen Aufruf ist teurer, und zu einem gewissen Grad, die alle Ersparnisse Finsternisse Sie verwenden anonyme Funktionen erhalten könnten. Jede Funktion fügt den Call-Stack genannt, die eine kleine, aber nicht triviale Menge an Overhead führt.

Aber es sei denn, Sie Verschlüsselungs- / Entschlüsselungs-Routinen oder etwas ähnlich empfindlich auf Leistung schreiben, wie viele andere haben festgestellt, es ist immer besser für elegant, leicht zu lesende Code über schnellen Code zu optimieren.

Angenommen, Sie gut architected Code schreiben, dann Fragen der Geschwindigkeit der Verantwortung derer sein sollte, die Dolmetscher / Compiler zu schreiben.

Wenn wir eine Auswirkung auf die Leistung im Betrieb erklärt Funktionen haben können. Hier ist ein Benchmark deklarieren Funktionen in Zusammenhang mit einer anderen Funktion oder außerhalb:

http://jsperf.com/function-context-benchmark

In Chrome ist der Betrieb schneller, wenn wir die Funktion außerhalb erklären, aber in Firefox ist es das Gegenteil.

Im anderen Beispiel sehen wir, dass, wenn die innere Funktion nicht eine reine Funktion ist, wird es einen Mangel an Leistung auch in Firefox: http://jsperf.com/function-context-benchmark-3

Was wird auf jeden Fall Ihre Schleife macht schneller in einer Vielzahl von Browsern, vor allem IE-Browser, wird Looping wie folgt:

for (var i = 0, iLength = imgs.length; i < iLength; i++)
{
   // do something
}

Sie haben in einer beliebigen 1000 in den Schleifenzustand versetzt, aber du was ich meine, wenn man durch alle Elemente im Array gehen wollte.

eine Referenz fast immer geht langsamer zu sein als die Sache es beziehen. Denken Sie daran, auf diese Weise - sagen wir Ihnen das Ergebnis der Addition 1 + 1 drucken möchten, die mehr Sinn macht:

alert(1 + 1);

oder

a = 1;
b = 1;
alert(a + b);

Ich weiß, das ist eine wirklich simple Art und Weise, sie zu betrachten, aber es ist illustrativ, nicht wahr? Verwenden Sie eine Referenz nur, wenn es wird mehrmals verwendet werden - zum Beispiel, welche diese Beispiele machen mehr Sinn:

$(a.button1).click(function(){alert('you clicked ' + this);});
$(a.button2).click(function(){alert('you clicked ' + this);});

oder

function buttonClickHandler(){alert('you clicked ' + this);}
$(a.button1).click(buttonClickHandler);
$(a.button2).click(buttonClickHandler);

Das zweite ist besser Praxis, auch wenn es mehr Zeilen bekam ist. Hoffentlich all dies ist hilfreich. (Und die jquery Syntax niemanden abwerfen hat)

@nickf

(ich wünsche, den rep musste einfach einen Kommentar, aber ich habe nur gefunden gerade diese Seite)

Mein Punkt ist, dass es Verwirrung hier zwischen dem Namen / anonymen Funktionen und dem Anwendungsfall der Ausführung ist + in einer Iteration zu kompilieren. Wie ich erläutert, mit dem Namen der Unterschied zwischen Anon + an sich unbedeutend ist -. Ich sage es der Anwendungsfall ist die fehlerhaft ist

Es scheint mir offensichtlich, aber wenn nicht, dass ich der beste Rat „nicht dumm Dinge tun“ (von dem die konstante Blockschalt + Objekterstellung dieses Anwendungsfall ist ein), und wenn Sie nicht sicher sind , Test!

YES! Anonyme Funktionen sind schneller als normale Funktionen. Vielleicht, wenn die Geschwindigkeit von größter Bedeutung ist ... wichtiger als Wiederverwendung von Code dann betrachtet anonyme Funktionen.

Es ist ein wirklich guter Artikel über Javascript und anonyme Funktionen optimieren hier:

http://dev.opera.com/articles/ view / effizient-javascript /? page = 2

@nickf

obwohl

Das ist ein ziemlich alberner Test, sind Sie die Ausführung zu vergleichen und Zusammenstellung Zeit gibt, die offensichtlich Methode kosten werden 1 (kompiliert N-mal, JS Motor abhängig) mit Methode 2 (kompiliert einmal ). Ich kann kein JS Entwickler vorstellen, die ihre Bewährungs das Schreiben von Code in einer solchen Art und Weise passieren würde.

Ein weitaus realistischer Ansatz ist die anonyme Zuordnung, wie in der Tat Sie verwenden für Ihre document.onclick Methode eher wie das ist folgendes, die in der Tat leicht die Anon Methode begünstigt.

einen ähnlichen Test-Framework zu Ihnen verwenden:


function test(m)
{
    for (var i = 0; i < 1000000; ++i) 
    {
        m();
    }
}

function named() {var x = 0; x++;}

var test1 = named;

var test2 = function() {var x = 0; x++;}

document.onclick = function() {
    var start = new Date();
    test(test1);
    var mid = new Date();
    test(test2);
    var end = new Date();
    alert ("Test 1: " + (mid - start) + "ms\n Test 2: " + (end - mid) + "ms");
}

Wie in den Kommentaren darauf hingewiesen Antwort auf @nickf: Die Antwort auf

  

ist die Schaffung einer Funktion einmal schneller als eine Million Mal zu schaffen

ist einfach ja. Aber wie seine JS perf zeigt, ist es nicht langsamer um den Faktor eine Million, was zeigt, dass es tatsächlich schneller im Laufe der Zeit bekommt.

Die interessantere Frage ist für mich:

  

Wie funktioniert ein wiederholten erstellen + ausführen vergleichen einmal erstellen + wiederholt Ausführen .

Wenn eine Funktion eine komplexe Berechnung der Zeit führt die Funktion Objekt zu erstellen ist sehr wahrscheinlich vernachlässigbar. Aber was ist mit dem über den Kopf von erstellen in Fällen, in denen run schnell ist? Zum Beispiel:

// Variant 1: create once
function adder(a, b) {
  return a + b;
}
for (var i = 0; i < 100000; ++i) {
  var x = adder(412, 123);
}

// Variant 2: repeated creation via function statement
for (var i = 0; i < 100000; ++i) {
  function adder(a, b) {
    return a + b;
  }
  var x = adder(412, 123);
}

// Variant 3: repeated creation via function expression
for (var i = 0; i < 100000; ++i) {
  var x = (function(a, b) { return a + b; })(412, 123);
}

Der JS Perf zeigt, dass nur ein einziges Mal die Funktion zu schaffen ist schneller als erwartet. Aber auch bei einem sehr schnellen Betrieb wie ein einfaches Hinzufügen, die Overhead die Funktion wiederholt zu schaffen sind nur wenige Prozent.

Der Unterschied wird wahrscheinlich nur in den Fällen signifikant, wo die Funktion Objekt Erstellung komplexer ist, während eine vernachlässigbare Laufzeit aufrechterhalten wird, beispielsweise wenn der gesamte Funktionskörper in eine if (unlikelyCondition) { ... } gewickelt ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top