Node.js basiert auf libuv , einer plattformübergreifenden Bibliothek, die apis / syscalls für asynchrone (nicht blockierende) Ein- / Ausgaben abstrahiert, die von den unterstützten Betriebssystemen (mindestens Unix, OS X und Windows) bereitgestellt werden.
Asynchrone E / A.
In diesem Programmiermodell blockieren Öffnungs- / Lese- / Schreibvorgänge auf Geräten und Ressourcen (Sockets, Dateisysteme usw.), die vom Dateisystem verwaltet werden , nicht den aufrufenden Thread (wie im typischen synchronen c-ähnlichen Modell) und markieren nur die Prozess (in der Datenstruktur auf Kernel- / Betriebssystemebene), der benachrichtigt wird, wenn neue Daten oder Ereignisse verfügbar sind. Im Falle einer Webserver-ähnlichen App ist der Prozess dann dafür verantwortlich, herauszufinden, zu welcher Anforderung / welchem Kontext das gemeldete Ereignis gehört, und die Anforderung von dort aus zu verarbeiten. Beachten Sie, dass dies zwangsläufig bedeutet, dass Sie sich auf einem anderen Stapelrahmen befinden als dem, von dem die Anforderung an das Betriebssystem stammt, da dieser einem Prozess-Dispatcher nachgeben musste, damit ein einzelner Thread-Prozess neue Ereignisse verarbeiten kann.
Das Problem mit dem von mir beschriebenen Modell ist, dass es für den Programmierer nicht vertraut und schwer zu überlegen ist, da es nicht sequentieller Natur ist. "Sie müssen eine Anfrage in Funktion A stellen und das Ergebnis in einer anderen Funktion verarbeiten, in der Ihre Einheimischen von A normalerweise nicht verfügbar sind."
Knotenmodell (Continuation Passing Style und Event Loop)
Node behebt das Problem, indem die Sprachfunktionen von Javascript genutzt werden, um dieses Modell ein wenig synchroner zu gestalten, indem der Programmierer veranlasst wird, einen bestimmten Programmierstil zu verwenden. Jede Funktion, die E / A anfordert, hat eine Signatur wie function (... parameters ..., callback)
und muss einen Rückruf erhalten, der aufgerufen wird, wenn der angeforderte Vorgang abgeschlossen ist (denken Sie daran, dass die meiste Zeit darauf gewartet wird, dass das Betriebssystem die Fertigstellung signalisiert - die Zeit, die sein kann verbrachte andere Arbeit). Durch die Unterstützung von Javascript für Schließungen können Sie Variablen verwenden, die Sie in der äußeren (aufrufenden) Funktion innerhalb des Rückrufkörpers definiert haben. Auf diese Weise können Sie den Status zwischen verschiedenen Funktionen beibehalten, die von der Knotenlaufzeit unabhängig voneinander aufgerufen werden. Siehe auch Continuation Passing Style .
Darüber hinaus return
steuert die aufrufende Funktion nach dem Aufrufen einer Funktion, die eine E / A-Operation erzeugt, normalerweise die Ereignisschleife des Knotens . Diese Schleife ruft den nächsten Rückruf oder die nächste Funktion auf, deren Ausführung geplant war (höchstwahrscheinlich, weil das entsprechende Ereignis vom Betriebssystem benachrichtigt wurde). Dies ermöglicht die gleichzeitige Verarbeitung mehrerer Anforderungen.
Sie können sich die Ereignisschleife des Knotens als etwas ähnlich wie den Dispatcher des Kernels vorstellen: Der Kernel würde die Ausführung eines blockierten Threads planen, sobald seine ausstehende E / A abgeschlossen ist, während der Knoten einen Rückruf plant, wenn das entsprechende Ereignis aufgetreten ist.
Sehr gleichzeitig, keine Parallelität
Als letzte Bemerkung macht der Ausdruck "alles läuft parallel außer Ihrem Code" eine anständige Aufgabe, den Punkt zu erfassen, an dem der Knoten Ihrem Code ermöglicht, Anforderungen von Hunderttausenden offenen Sockets mit einem einzigen Thread gleichzeitig zu verarbeiten, indem alle Ihre js gemultiplext und sequenziert werden Logik in einem einzigen Ausführungsstrom (obwohl die Aussage "alles läuft parallel" hier wahrscheinlich nicht korrekt ist - siehe Parallelität vs. Parallelität - Was ist der Unterschied? ). Dies funktioniert ziemlich gut für Webapp-Server, da die meiste Zeit tatsächlich für das Warten auf Netzwerk oder Festplatte (Datenbank / Sockets) aufgewendet wird und die Logik nicht wirklich CPU-intensiv ist - das heißt: Dies funktioniert gut für E / A-gebundene Workloads .