Der Unterschied ist, dass Sie nur forEach
zu Konstrukt die optimierte Funktion verwenden. Sobald die Funktion erstellt wurde, gibt es keine Schleifen innerhalb: loop is unrolled und Spaltennamen sind hardcoded. Die Methode wird dann in eine Arbeitsfunktion eval
ed, die sogar in Maschinencode depending on the engine kompiliert werden könnte. Daraus ergeben sie zwei Leistungsverbesserungen:
- Durch die
for
Schleife Bedingungsprüfung Entfernen (i < columns.length
) vollständig, gibt es keine Verzweigung, und
- Durch Werte von
column[i].name
in mehrere Anweisungen zu, entfernen Sie column[i]
und Lookups Auswertung zu column.name
in jedem Schritt.
So nach new Function(...)
mit dem Code als String
geben Aufruf, Ihre parseRow
Variable erhält den Verweis auf die folgende Funktion:
function parseRow(columns, parser) {
return {
"columnOne": parser.readColumnValue(),
"columnTwo": parser.readColumnValue(),
"columnThree": parser.readColumnValue(),
...
};
}
Beachten Sie, dass es keine Schleifen, Verzweigungen oder andere Lookups in diesem Code, außer für die multiple parser.readColumnValue()
Anrufe.
Warum ist das in JavaScript möglich?
Der Grund, warum dies in JavaScript so effizient funktioniert, ist, weil JavaScript-Quellcode in jeder Webseite von der JS-Engine sowieso interpretiert oder kompiliert werden muss. Sie liefern Ihre Webseite nicht mit kompilierten ausführbaren Dateien oder sogar (noch) vorkompiliertem Bytecode (wie Java oder .NET).Jedes Mal, wenn eine neue .js
Datei geladen wird, kompiliert Ihr Browser sie von Grund auf neu, bevor Sie sie ausführen (naja, in modernen Suchmaschinen ist es etwas zwischen dem Interpretieren und Kompilieren, d. H. JITting).
Das bedeutet, dass das Erstellen einer Arbeitsfunktion aus einer Zeichenfolge (d. H. Das Kompilieren des Codes) während der Laufzeit nicht weniger effizient ist als das Lesen von handgeschriebenem Code aus der JS-Datei. Vergleichen Sie das mit einem C/C++ - Programm, das (in allen sinnvollen Fällen) zu Maschinencode kompiliert wurde (d. H. Ausführbare Datei, die der CPU so nahe kommt wie möglich) before it reaches the customer.
Wenn Sie dies in C++ (eine Art von self-modifying code) tun möchten, müssten Sie einen Compiler entlang Ihrer App bündeln, um den Code zu bauen, und die Kosten für den Aufbau dieser Funktion würden die Vorteile übergewichten Du würdest es endlich anfangen. In .NET zum Beispiel ist es auch nicht ungewöhnlich für ein Programm emit methods or even assemblies at run time, das dann JIT kompiliert, um Maschinencode zu kompilieren, der mögliche Leistungsverbesserungen wie die in Ihrer Frage ermöglicht.
Geht es um 20% Gewinn mit der Funktionserstellungslogik selbst? Oder bei jedem Aufruf der Funktion parseRow? Wenn es der letztere Fall ist, würde ich annehmen, dass die Verstärkung aufgrund des Fehlens von for-Schleife in optimiertem Code geschieht. (Im ersten Fall würde die for-Schleife mit jedem Aufruf der parseRow-Funktion ausgeführt werden. Auch mehrere Aufrufe der columns.length-Eigenschaft könnten auf die Langsamkeit des ursprünglichen Codes zurückgeführt werden. Nur meine 2 Cent :)) –
(für V8) http : //www.youtube.com/watch? v = UJPdhx5zTaw –
Wenn die Größe von 'Spalten' groß genug ist, scheint der 'optimierte Code' nicht schneller zu sein. siehe [jsPerf] (http://jsperf.com/javascript-optimization-with-new-function) – rhgb