Blog

NodeJS - Das Was, Warum, Wie und Wann

Freek Wielstra

Aktualisiert Oktober 22, 2025
14 Minuten

Was ist NodeJS? Die fünf Worte, mit denen NodeJS auf der eigenen Website beworben wird, lauten "Evented I/O for V8 Javascript". Was das genau bedeutet, erfahren Sie im Wie. NodeJS ist, kurz gesagt, ein serverseitiges Anwendungsframework mit dem Schwerpunkt auf hoher gleichzeitiger Leistung. Für Node geschriebene Anwendungen werden in einem ereignisbasierten Single-Thread-Prozess ausgeführt. Node ist ein Open-Source-Projekt, das Anfang 2009 von Ryan Dahl konzipiert und entwickelt wurde und sich seitdem in aktiver Entwicklung befindet. Joyent, Dahls Arbeitgeber, unterstützt und sponsert das Projekt.

Derzeit ist die Hauptzielplattform Linux. Es wird daran gearbeitet, auch Windows und Mac zu unterstützen, aber ich glaube, das zielt hauptsächlich darauf ab, mehr Entwickler für Node zu gewinnen.

Bevor wir in die Tiefe gehen, lassen Sie uns erklären, was wahrscheinlich der Kernpunkt von NodeJS ist - ereignisbasierte E/A.

In der Vergangenheit haben Sie eine einfache Anwendung wie diese geschrieben:

puts("Bitte geben Sie Ihren Namen ein: ");
var name = gets();
puts("Hallo, " + Name);

Das Kernstück ist der Aufruf "gets()". Damit wird die gesamte Anwendung blockiert, bis der Benutzer einige Daten eingibt. Oft werden die Daten auf ähnliche Weise aus externen Quellen wie Datenbanken abgerufen:

var results = db.query("select x from y");

Das Programm bleibt, wie bei der Verwendung von gets(), in dieser Zeile stehen, bis die Methode db.query() zurückkehrt, die wiederum den Datenbankserver kontaktiert, die Abfrage auslöst und auf die Antwort wartet. Die Schlüsselwörter hierbei sind 'halten' und 'warten' - das Programm dreht quasi Däumchen, während es auf Benutzereingaben oder eine Antwort vom Datenbankserver wartet. Die ereignisbasierte Programmierung geht hier anders vor. Wenn Sie die blockierende Operation aufrufen, übergeben Sie ihr ein zusätzliches Argument: einen Codeblock, der ausgeführt werden soll, wenn die Operation abgeschlossen ist. Anstatt auf eine Antwort des Benutzers oder der Datenbank zu warten, setzt die Anwendung ihre Ausführung fort. Dieser Ablauf ist mit Javascript ziemlich einfach. Hier sehen Sie, wie die beiden obigen Operationen aussehen, wenn sie ereignisbasiert in Javascript geschrieben sind:

puts("Geben Sie Ihren Namen ein: ");
  gets(function (Name) {
  setzt("Hallo, " + Name);
});
db.query("select x from y", function (result) {
  // Ergebnis verwenden
});

Der wichtige Teil ist das zusätzliche Argument, das Sie an die blockierenden Methoden übergeben. Damit teilen Sie der Methode im Grunde mit: "Okay, du machst das und wenn du fertig bist, führe diese Methode aus". In der Zwischenzeit läuft die 'Hauptanwendung' weiter, während ein Hintergrundprozess auf Benutzereingaben oder die Rückgabe des Ergebnisses durch die Datenbank wartet. Wenn die obige Methode ausgeführt wird, führt der Prozess die Abfrage aus und verarbeitet ihr Ergebnis, auch wenn er auf die Benutzereingabe wartet. Ebenso kann er die Benutzereingabe verarbeiten, während er noch darauf wartet, dass die Datenbankabfrage ein Ergebnis liefert. NodeJS ist auf diesem Ansatz aufgebaut. Da es bei E/A niemals blockiert, führt es den Code schnell aus. Wir werden uns das im Abschnitt Warum genauer ansehen.

Warum

Warum ereignisgesteuerte E/A? Die kurze Antwort: Die Latenzzeit. Werfen Sie einen Blick auf die folgende Tabelle, in der die Anzahl der CPU-Zyklen aufgeführt ist, die für den Zugriff auf Daten benötigt werden:

L1-Cache3 Zyklen
L2-Cache14 Zyklen
RAM250 Zyklen
DISK41.000.000 Zyklen
NETZWERK240.000.000 Zyklen
Die Tabelle wurde schamlos aus Dahls Präsentationen kopiert, bitte zitieren Sie mich nicht zu diesen Zahlen.

Was soll das bedeuten? Im Endeffekt bedeutet dies, dass klassische, blockierende Prozesse 41.000.000 CPU-Zyklen lang Däumchen drehen, während sie darauf warten, dass etwas von der Festplatte geladen wird. Diese Prozesse können nichts anderes tun, während sie Däumchen drehen, so dass im Falle eines Webservers andere Anfragen pausiert werden, bis die Anwendung ihre Daten erhalten hat. Die klassische Lösung für dieses Problem: Fügen Sie mehr Prozesse hinzu. Wenn ein Prozess Däumchen dreht und auf Daten wartet, kann der andere Prozess übernehmen und die nächste Anfrage bearbeiten. Bei 200 Prozessen, die für die Bearbeitung von Anfragen zur Verfügung stehen, müssen die Verbraucher nie lange in der Warteschlange warten, bis ihre Anfrage vom nächsten freien Prozess bearbeitet wird. Aber das hat seine Grenzen. Sogar harte Grenzen, die in der Vergangenheit die Ursache für viele Ausfälle waren. Was ist, wenn es im Netzwerk aus irgendeinem Grund zu einer großen Verzögerung kommt? Was ist, wenn mehr neue Anfragen pro Sekunde eintreffen, als die Datenbank verarbeiten kann? Die 200 Prozesse werden blockiert, sobald sie den Punkt erreichen, an dem sie Daten aus dem Netzwerk abrufen, und wenn sie alle belegt sind, stellt der Webserver die Bearbeitung der Anfragen einfach ein, die Benutzer nehmen sich eine Auszeit und auf Twitter erscheinen Meldungen wie "IS #SOMESITE.COM DOWN? #FML". Wie löst Node dieses Problem? Nun, um es einfach auszudrücken, er dreht nicht Däumchen. Er sagt: "Gut, unterliegendes System, gib mir diese Informationen aus dem Netzwerk. Ich werde etwas Nützliches tun. Sag mir Bescheid, wenn du fertig bist, ja? In Ordnung.' Und dann tut es etwas Nützliches, z.B. die nächste Anfrage bearbeiten. In diesem "Lass mich wissen, wenn du fertig bist" liegt der Kern der Leistung von NodeJS. Anstatt darauf zu warten, dass etwas abgerufen wird (blockierend), läuft es weiter (nicht-blockierend). Auf diese Weise werden keine kostbaren CPU-Zyklen mit Warten verschwendet. Da es nicht blockiert, besteht auch ein deutlich geringerer Bedarf an der Ausführung mehrerer Prozesse. Er läuft einfach weiter, unabhängig davon, wie viele Anfragen er zu bearbeiten hat. Wenn er eine Bazillion Anfragen erhält, gehen ihm nicht die Prozesse aus oder eine andere willkürliche Grenze, sondern er bearbeitet einfach jede einzelne. Er bearbeitet jedes Ereignis, das ausgelöst wird, eines nach dem anderen, und zwar sehr schnell. Es ist wie bei einer Essensbestellung. Sie treten an den Tresen Ihres Fast-Food-Ladens und bestellen einen Hamburger. Klassischerweise stehen Sie dort und warten, bis der Koch fertig ist und Ihnen Ihre Bestellung übergibt, während sich andere hinter Ihnen anstellen. Bei der Multi-Thread-Methode stellt der Laden mehr Kellner und Köche ein, die jeweils einen Kunden auf einmal bedienen können. Bei der Non-Blocking-Methode lächelt der Kellner und sagt: "In Ordnung, Sir, bitte nehmen Sie einen Platz, Ihre Bestellung wird Ihnen gebracht, sobald sie fertig ist. Der Nächste!". Und so geht es weiter. Der Kellner gibt die Bestellung an die Küche weiter, die Küche bereitet Ihren Burger zu und eine hübsche Serviererin bringt Ihnen Ihren Hamburger, wenn er fertig ist. Die Schlange ist schnell vorbei, denn alles, was die Bedienung tut, ist, die Bestellung der Leute entgegenzunehmen und weiterzugeben. Wenn Fast Food-Läden nur so funktionieren würden.

Warum Javascript?

Sie schreiben NodeJS in Javascript, und ein großer Teil der Node-Standardbibliothek ist ebenfalls in Javascript geschrieben. Warum ist das so? Was macht Javascript zur besten Lösung für dieses Problem? Es ist ja nicht so, dass Javascript die einzige Sprache mit erstklassigen Funktionen, Closures usw. ist. Dafür gibt es ein paar Gründe, die mir bekannt sind, und wahrscheinlich gibt es noch mehr, die ich nicht erwähne. Erstens sind Ereignisbehandlung, Rückrufe und asynchrones Verhalten ihr Kern. In seinem natürlichen Lebensraum, dem Browser, wird es schon seit Jahren auf diese Weise verwendet. Das Öffnen einer Datei oder einer Netzwerkressource und die Übergabe eines Callbacks an diese Methode unterscheidet sich nicht wesentlich vom Auslösen eines AJAX-Aufrufs mit einem Callback - es ist sogar genau dasselbe. Der Browser ist von Natur aus asynchron, da so ziemlich jeder Teil der Logik auf Benutzereingaben, Netzwerk-E/A oder etwas Einfacheres wie ein zeitlich festgelegtes Ereignis angewiesen ist - jedes dieser Elemente würde die Ausführung des Skripts blockieren, wenn es mit blockierenden Operationen ausgeführt würde, und das ist das Letzte, was Sie in einer benutzerfreundlichen Anwendung wie einem Webbrowser wollen. Die Behandlung von Ereignissen ist das Herzstück sowohl von Javascript als Sprache als auch als Denkweise für Javascript-Entwickler, was ein weiterer wichtiger Grund für die Verwendung von Javascript ist: Es ist vielen Entwicklern vertraut. Javascript ist so etwas wie ein Ninja unter den Programmiersprachen - die meisten Menschen wissen nicht, dass es eine der meistgenutzten Programmiersprachen überhaupt ist. Ihre Popularität hat in den letzten zehn Jahren erheblich zugenommen, mit dem Aufkommen von AJAX, hochgradig interaktiven und reaktionsschnellen Webanwendungen, Streaming-Updates und großen Unternehmen wie Google, die Webanwendungen als primäre Plattform für alle Arten von Anwendungen vorantreiben. Das Herzstück von all dem ist Javascript. Es gibt einfach keine andere Sprache für die clientseitige Entwicklung im Web, im Gegensatz zu einer Bazillion Sprachen und Frameworks auf der Serverseite. Aus diesem Grund gibt es eine riesige Menge an Javascript-Kenntnissen und -Erfahrungen, so dass die Sprache selbst kein großes Problem darstellt, wenn man sie auf die Serverseite überträgt. Ein dritter, aber fragwürdiger Grund ist, dass es eine einfache Sprache ist. Keine großen Architekturen, tief verschachtelte Objekthierarchien, komplexe Syntax oder zwanzig verschiedene Syntaxen, um effektiv das Gleiche zu erreichen. Ich möchte jedoch keinen Sprachenkrieg entfachen, also werde ich auf dieses Argument nicht weiter eingehen. Der letzte Grund, der mir einfällt: Die Wiederverwendung von Code. Node kennt Javascript und Ihr Browser auch, so dass es sehr sinnvoll ist, wenn die beiden ihren Code gemeinsam nutzen. Es gibt noch einen dritten Grund: JSON. Viele Webservices bieten heutzutage JSON als Ausgabeformat an, und es ist ein recht beliebtes Datenaustauschformat. Javascript ist JSON, so dass es sowohl auf dem Server als auch auf den Clients ein großes Plus ist. Dann gibt es noch Backend-Speichersysteme wie MongoDB, die ebenfalls JSON als Sprache für den Datenaustausch (und manchmal sogar für die Speicherung) verwenden. Nichts macht mehr Sinn, als JSON und Javascript zusammen zu verwenden, und die Möglichkeit, JSON-Objekte in der eigenen Sprache zu erstellen und zu verarbeiten, ist ein großes Plus. Damit ist die nächste Frage geklärt: Warum ist eine NodeJS-Anwendung single-threaded?

Warum single-threaded?

Ich sehe, dass Sie denken. Wenn Node in einem einzelnen Thread so schnell ist, warum nicht die beiden Vorteile kombinieren und es zu einem Multi-Thread-System machen? Nun, erstens wäre es nicht wesentlich schneller und zweitens würde es Ihre Anwendung (und auch Node selbst) viel komplexer machen. Sie müssten sich mit mehreren Threads befassen, die auf dieselbe Ressource zugreifen, entscheiden, welcher Thread das nächste Ereignis bearbeiten soll, und ich bin sicher, dass denjenigen unter Ihnen, die Erfahrung mit großer, nebenläufiger Software haben, eine ganze Liste von Problemen einfällt, die in einer Multi-Thread-Anwendung gelöst werden müssen. Die Vorteile einer Single-Thread-Anwendung liegen darin, dass der Prozessor nicht den Overhead des Kontextwechsels hat (wenn ein Thread CPU-Zeit erhält, während der andere pausiert). Es gibt keine Heap-Allokationen oder Forks oder Startsequenzen, die bei der Erstellung eines neuen Threads durchgeführt werden müssen. Außerdem gibt es natürlich den offensichtlichen Vorteil, dass Sie nicht mit dem Gedanken an Gleichzeitigkeit programmieren müssen. Weniger Kopfschmerzen, weniger schwer aufzuspürende Fehler, weniger spezifisches Wissen und Verständnis erforderlich usw. Aber was ist mit moderner Hardware? Die gängigen CPU-Hersteller bauen keine Single-Core-Prozessoren mehr, sondern nur noch schicke Dual-, Quad-, Hexa- und Octacores, und in naher Zukunft sollen noch mehr Kerne und Spezialkomponenten hinzukommen. Nun, das ist kein Problem. Ein Node-Programm ist zwar ein Single-Thread-Programm, aber nichts hindert Sie daran, mehrere Node-Prozesse zu erstellen und sie nebeneinander laufen zu lassen, wobei jeder einen einzelnen Kern verwendet. Schalten Sie einen Loadbalancer oder einen Reverse Proxy wie nginx davor, entweder auf demselben Server oder extern, und schon sind Sie fertig. Sie könnten sogar einen anderen Node-Prozess als Loadbalancer verwenden. Dazu müssten Sie natürlich ein Backend-Speichersystem verwenden, das gleichzeitige Anfragen (d.h. von mehreren Node-Prozessen) verarbeiten kann. Jetzt kennen Sie also eine Reihe von "Warum" und fragen sich vielleicht das "Wie" - Wie erreicht Node all dies? Das werden wir uns im nächsten Abschnitt ansehen.

Wie: Unter der Haube

Wie funktioniert es also? Was sorgt dafür, dass Javascript schnell genug ausgeführt wird, um mit anderen Lösungen konkurrieren zu können? Wie interagiert es mit dem System, auf dem es läuft? NodeJS basiert auf V8, der Javascript-Engine von Google, die auch den Chrome-Browser antreibt, der die schnellste Javascript-Ausführungsgeschwindigkeit aufwies und die Javascript-Leistung beim Vergleich von Browsern ganz nach vorne brachte, wodurch die Geschwindigkeit zu einem wichtigen Marketingfaktor für Browser wurde. Aber V8 kann auch außerhalb des Browsers laufen und wurde als Open-Source-Projekt erweitert, um NodeJS zu schaffen. Node fügt einen Thread-Pool (unter Verwendung von libeio), eine Ereignisschleife (libevent) und ausgefallene Dinge wie DNS-Auflösung und Kryptographie hinzu. Darüber hinaus gibt es eine Reihe von Node-Bindings für E/A (Sockets, HTTP usw.). Und schließlich gibt es eine Standardbibliothek für so ziemlich alles, was Sie in reinem Javascript brauchen. Machen Sie sich ein Bild:

Wenn Sie neugierig auf das Innenleben von Node sind, ist der Node-Code Open Source und kann aus dem Github-Repository geklont werden.

Eine Node-Anwendung

Das Angenehme an NodeJS ist, dass es im Grunde nur ein Skript-Interpreter ist - Sie erstellen ein .js-Skript, rufen 'node script.js' auf und es wird ausgeführt. Es kompiliert das Skript (wahrscheinlich) im Hintergrund, aber als Entwickler merken Sie das kaum - es startet einfach. In Ihrem Skript richten Sie in der Regel die Umgebung ein, laden einige Bibliotheken und richten eine Art Listener ein - zum Beispiel einen HTTP-Server. Hier ist ein Beispiel für den einfachsten HTTP-Webserver, der die interne Bibliothek von NodeJS verwendet, mit Kommentaren, die erklären, was jede Zeile tut:

// Binden Sie das HTTP-Modul ein. NodeJS implementiert den CommonJS-Standard zur Definition von 
// Eigenständige Anwendungsmodule und Bibliotheken.
var http = require('http');
// Erstellen Sie den HTTP-Server. Wir übergeben ihm eine Callback-Funktion, die ausgeführt wird, sobald 
// eine Anfrage eingegangen ist.
var server = http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hallo Weltn');
});
// Starten Sie den Server und lassen Sie ihn auf eingehende Verbindungen auf dem angegebenen Hostnamen und Port lauschen.
server.listen(1337, "127.0.0.1");
// Lassen Sie den Entwickler wissen, dass wir startklar sind.
console.log('Server läuft unter https://127.0.0.1:1337/');

Das obige Beispiel veranschaulicht ein paar Dinge: Grundlegende Methodenaufrufe (http.createServer, console.log), die Übergabe von Callback-Methoden (function(req, res)), das Node require System (require 'http') und den Objekttyp von Javascript, um eine Map mit Parametern zu erstellen, die an den Aufrufer zurückgegeben wird. Dieser Code kann einfach durch den Aufruf von 'node app.js' auf der Kommandozeile ausgeführt werden. Die Meldung, die den Benutzer darüber informiert, dass der Server läuft, erscheint und der Server ist betriebsbereit. So einfach ist das.

Wenn

Jetzt, da Sie wissen, was Node ist und was es ausmacht, haben Sie vielleicht eine gute Vorstellung davon, wofür Sie es einsetzen können. Am häufigsten wird es als Backend für Webanwendungen eingesetzt, aber Sie können es für so ziemlich jede Anwendung verwenden, auch wenn der Schwerpunkt weiterhin auf E/A liegt - es gibt wahrscheinlich bessere Sprachen und Lösungen für z.B. wissenschaftliche Berechnungen oder die Verarbeitung von Geschäftsregeln oder was auch immer. In der Praxis fallen jedoch viele der heutigen (Web-)Anwendungen in die E/A-Kategorie - Benutzer, die Daten abfragen, Benutzer, die Daten hinzufügen und bearbeiten. NodeJS ist kein goldener Hammer. Es ist nicht die leistungsstärkste Lösung, es ist keine Einheitslösung und ich empfehle Ihnen nicht, es in Ihr nächstes Projekt einzubauen, nur weil ich Ihnen sage, dass es fantastisch ist. Damit das klar ist, hier sind einige Anwendungsfälle, für die Node verwendet werden kann und in denen es sich auszeichnet:

  • Generisches Web-Framework. Es bietet alles, was Sie brauchen - serverseitige Logik, Konnektoren für Backend-Systeme (wie Datenbanken), Dateiservice, Parsing von Vorlagen (mit einer Vielzahl von Vorlagensprachen), Authentifizierung und vieles mehr.
  • Stark konkurrierende Websites - hochvolumige Webservices, wechselnde Belastungen usw.
  • Hochgradig gleichzeitige Verbindungen - zum Beispiel Websockets mit vielen Clients, die Daten senden und empfangen.
  • Backend-Systeme, die mit Dateien arbeiten. Beispiel: Nodeload von GitHub, das Git-Repositories für den Download vorbereitet, indem es sie in Tarballs komprimiert. Es ruft git archive auf, wartet und streamt dann das Ergebnis mit Hilfe der Stream-APIs von Node an den Benutzer zurück. (Ausgabe-E/A ist auch E/A und kann von ereignisgesteuerter E/A profitieren). Siehe https://github.com/blog/900-nodeload2-downloads-reloaded.

Ich bin mir sicher, dass es viele Anwendungsfälle gibt, in denen sich Node auszeichnen kann. Wenn Sie neugierig sind, wofür Node heutzutage verwendet wird, werfen Sie einen Blick auf Projekte, Anwendungen und Unternehmen, die Node verwenden, im NodeJS-Wiki auf Github. Beim nächsten Mal werden wir tiefer in das Node-Ökosystem eintauchen und uns die vielen interessanten Projekte genauer ansehen, die derzeit mit und für Node entwickelt werden. In der begleitenden XKE-Sitzung werden die Teilnehmer mit diesen Projekten spielen, halten Sie also ein Auge auf die Agenda.

Verfasst von

Freek Wielstra

Freek is an allround developer whose major focus has been on Javascript and large front-end applications for the past couple of years, building web and mobile web applications in Backbone and AngularJS.

Contact

Let’s discuss how we can support your journey.