2016-04-10 8 views
1

Basierend auf meinen aktuellen Annahmen über VMs und ihr Verhalten, ich denke, Schließungen sind zugeordnet und kompiliert jedes Mal, wenn ihre Definition getroffen wird; im Gegensatz zu Funktionen, die außerhalb von Closures deklariert sind, die einmal zugewiesen und kompiliert werden (weil sie irgendwo platziert sind, wird ihre Definition nur einmal getroffen). Ist diese Annahme richtig?Wann werden Schließungen in Node.js V8 zugeordnet und kompiliert?

Also, wenn ich eine Schließung in socket.on('data', function (data) {...}) habe, vergibt V8 neuen Speicher (und möglicherweise re-kompiliert) die Schließung jedes Mal Daten vom Socket empfangen werden?

Antwort

5

Ich stelle dar, Verschlüsse zugewiesen und jedes Mal, ihre Definition getroffen wird

zusammengestellt

Nicht wirklich. Verschlüsse werden einmal kompiliert, aber zugewiesen jedes Mal ihre Definition wird getroffen. Am wichtigsten ist, dass Sie die Zuordnung und die Kompilierung unterscheiden müssen.

  • Jede Funktion des Code (das heißt mit derselben Stelle im Quellcode) wird nur einmal kompiliert, auch wenn die Funktion mehrmals in verschiedenen Umgebungen instanziiert wird.
    Es wäre sinnlos, sich bei jeder Instantiierung zu kompilieren, genauso wie es sinnlos ist, für jeden einzelnen Aufruf kompilieren zu müssen (obwohl das im wörtlichen Sinne ein "Interpreter" ist) und die Grenzen fließend sind, zB für faule Kompilierung Zeitpunkt des ersten Anrufs).
    Code könnte erneut kompiliert werden (mit einem langsameren, aber komplexeren Compiler), wenn er zu einem Optimierungskandidaten wird oder wenn die Optimierung fehlschlägt und optimiert werden muss; aber das ist neben dem Punkt.

  • Jede Funktion wird zugewiesen/instanziiert, wenn ihre Definition getroffen wird. Dies ist besonders relevant für lokale Funktionen (verschachtelt in anderen Funktionen).
    Die Kosten für die Zuweisung für Nicht-Schließen-Funktionen ist jedoch Null, da kein Umgebungszeiger gespeichert werden muss, ein No-Object-Objekt benötigt wird.

Also, wenn ich einen Verschluss in socket.on('data', function (data) {...}) habe, weist V8 neuen Speicher (und möglicherweise neu compiliert) die Schließung jedes Mal Daten von der Socket empfangen werden?

Nicht die function (data) {…}, wird er nur einmal instanziert und an den on Aufruf übergeben.

Aber ja, wenn Sie eine Schließung haben, die im Teil instanziiert wird, dann wird das jedes Mal Speicher reservieren, wenn Daten empfangen werden und der Handler aufgerufen wird. Aber darüber müssen Sie sich keine Sorgen machen, die Speicherzuweisung ist billig und schnell.

Wenn Sie nach technischen Details suchen, empfehle ich http://mrale.ph/blog/2012/09/23/grokking-v8-closures-for-fun.html zu lesen (obwohl es schon ein paar Jahre alt ist).

+0

Wirklich technische Antwort. Danke für die Antwort. Ich habe Ihren Beitrag bearbeitet, um eine Zusammenfassung hinzuzufügen. Bitte sehen Sie, ob Sie damit einverstanden sind. –

+0

Und können Sie klären, was "verschiedene Umgebungen" bedeuten? Meinst du, wenn das gleiche Modul von mehreren anderen Modulen aufgerufen wird? Und Sie sagten, es gab eine Einschränkung: Optimierungskandidaten werden oft zusammengestellt. Was qualifiziert sich als "Optimierungskandidat"? –

+0

@Geotarget: Eine * lexikalische * Umgebung, der Umfang der Funktion, d. H. Die Sache, die der Verschluss schließt. Die Sache, die im Heap zugewiesen werden muss (im Gegensatz zum Stack für nicht geschlossene Umgebungen) und dass sich der Abschluss merken muss. – Bergi

2

Aufgrund meiner gegenwärtigen Annahmen über VM und ihr Verhalten, ich meine, Verschlüsse zugewiesen und jedes Mal, ihre Definition kompiliert wird getroffen;

rechts

im Gegensatz zu Funktionen deklariert außerhalb Verschlüssen, die einmal vergeben und kompiliert werden.

falsch, diese sind auch jedes Mal, ihre Definition kompiliert wird getroffen, aber sie sind in der Regel an einem Ort, wo ihre Definition nur einmal getroffen wird.
Verschlüsse sind so ausgelegt, dass sie mehrfach definiert werden und jedes Mal verschiedene Variablen/Werte einschließen.
Das ist, wie wir, ob es sich um eine einfache/anonyme Funktion oder ein Verschluss

V8 neuen Speicher reserviert jedes Mal Daten differentiatte

durch die Buchse empfangen werden

nein, diese anonyme Funktion wird einmal kompiliert und dann an den Event-Handler übergeben. Der Event-Handler hat nun einen Verweis auf diese Funktion und ruft sie jedes Mal auf, wenn Daten empfangen werden.

Die Definition in diesem Beispiel wird nur einmal beim Hinzufügen des Ereignis-Listeners getroffen.