Wie funktioniert Bluebird ' s util.toFastProperties Funktion, dass ein Objekt die Eigenschaften "schnell"?
In Bluebird ist util.js
- Datei, hat es folgende Funktion:
function toFastProperties(obj) {
/*jshint -W027*/
function f() {}
f.prototype = obj;
ASSERT("%HasFastProperties", true, obj);
return f;
eval(obj);
}
Für einige Grund, gibt es eine Anweisung nach der Rückkehr-Funktion, die ich bin mir nicht sicher, warum es ist da.
Als gut, es scheint, dass es ist gewollt, wie der Autor zum schweigen gebracht hatten, die JSHint Warnung dazu:
Unreachable 'eval' nach 'return'. (W027)
Was genau macht diese Funktion? Tut util.toFastProperties
wirklich, dass ein Objekt die Eigenschaften "schneller"?
Ich gesucht habe durch Bluebird ' s GitHub-repository für alle Kommentare in den source-code oder eine Erklärung in Ihre Liste der Fragen, aber ich konnte Sie nicht finden.
Du musst angemeldet sein, um einen Kommentar abzugeben.
2017 update: Erste, für die Leser heute kommt - hier ist eine version, die funktioniert mit Knoten 7 (4+):
Sans ein oder zwei kleine Optimierungen - alle die unten noch gültig ist.
Lassen Sie uns zuerst diskutieren, was es tut und warum, dass ist schneller, und dann, warum es funktioniert.
Was es tut,
V8-Motor mit zwei Objekt-Repräsentationen:
Hier ist eine einfache demo, der zeigt die Geschwindigkeit Unterschied. Hier verwenden wir die
delete
Aussage zu zwingen, die Objekte in langsamen Wörterbuch-Modus.Den Motor versucht zu verwenden, fast-Modus, Wann immer möglich und in der Regel immer dann, wenn viele property-Zugriff wird durchgeführt - jedoch ist es manchmal geworfen Wörterbuch-Modus. Wird im Wörterbuch-Modus hat einen großen performance-Strafe, also in der Regel ist es wünschenswert, Objekte im schnellen Modus.
Dieser hack soll Kraft, die das Objekt in den schnellen Modus aus der Wörterbuch-Modus.
, Warum es schneller
In JavaScript-Prototypen in der Regel speichern von Funktionen, die gemeinsam von vielen Fällen und nur selten ändern sich sehr dynamisch. Aus diesem Grund ist es sehr wünschenswert, wenn Sie in den schnell-Modus zu vermeiden, die zusätzliche Strafe jedes mal, wenn eine Funktion aufgerufen wird.
Für diese - v8 stellen Ihnen gerne Objekte, die
.prototype
Eigenschaft von Funktionen im schnellen Modus, da Sie geteilt werden, indem jedes Objekt erstellt, indem die Funktion wie ein Konstruktor. Dies ist in der Regel eine kluge und wünschenswerte Optimierung., Wie es funktioniert
Lassen Sie uns zuerst durch den code gehen und herauszufinden, was jede Zeile bedeutet:
Wir nicht haben zu finden, den code selbst zu behaupten, dass ein v8 macht diese Optimierung können wir statt Lesen Sie die v8-unit-tests:
Lesen und ausführen dieser test zeigt uns, dass diese Optimierung funktioniert in v8. Jedoch - es wäre schön zu sehen, wie.
Wenn wir
objects.cc
finden wir die folgende Funktion (L9925):Nun
JSObject::MigrateSlowToFast
nur explizit nimmt das Wörterbuch und wandelt es in eine schnelle V8-Objekt. Es ist eine ergiebige Lektüre und einen interessanten Einblick in die v8-Objekt - Interna- aber es ist nicht das Thema hier. Ich noch wärmstens empfehlen Lesen Sie es hier, wie es ist ein guter Weg zu lernen über v8-Objekte.Wenn wir check-out
SetPrototype
imobjects.cc
können wir sehen, dass es aufgerufen wird in Zeile 12231:Was wiederum heißt, indem
FuntionSetPrototype
das ist, was wir bekommen mit.prototype =
.Tun
__proto__ =
oder.setPrototypeOf
hätte das auch geklappt, aber diese sind ES6-Funktionen und Bluebird läuft auf allen Browser seit Netscape 7 so, das ist aus der Frage zur Vereinfachung der code hier. Wenn wir zum Beispiel überprüfen.setPrototypeOf
können wir sehen:Welche direkt auf
Object
:Also - wir gingen den Pfad aus der code-PET ' ka schrieb bis auf das blanke Metall. Das war schön.
Haftungsausschluss:
Daran erinnern, alle detail. Leute wie Petka sind die Optimierung freaks. Denken Sie immer daran, dass die vorzeitige Optimierung ist die Wurzel allen übels 97% der Zeit. Bluebird hat etwas ganz grundlegendes sehr oft so gewinnt es eine Menge von diesen performance-hacks - so schnell wie Rückrufe ist nicht einfach. Sie selten haben, etwas zu tun, wie dies in code, der nicht die Leistung einer Bibliothek.
eval
(in der code-Kommentare bei der Erläuterung der OP-code gepostet): "verhindern, dass die Funktion optimiert wird durch die dead code elimination oder weitere Optimierungen. Dieser code wird nie erreicht, aber selbst unreachable code bewirkt, dass v8 nicht optimieren Funktionen." . Hier ist ein Zusammenhang zu Lesen. Möchten Sie mich zu erarbeiten, weiter über das Thema?eval
das macht es nützlich in diesem Zusammenhang? Wenn es nur Toter code, wäre das nicht eine einfache Anweisung, wie1;
ausreichend?1;
würde nicht zu einer "deoptimization", eindebugger;
hätte wahrscheinlich genauso gut funktioniert. Das schöne ist, dass, wenneval
ist vergangen, etwas, das nicht ist eine Zeichenfolge, es hat nichts mit, also ist es eher harmlos - eine Art, wieif(false){ debugger; }
eval
entfernt wird - aber ehrlich, die Auswirkungen auf die Leistung auf der client-Seite ist winzig. Dies ist in der Tat ein problem, nur nicht groß.