EMZETT.
Login

Kurz: Node.js führt JavaScript außerhalb des Browsers aus, auf Servern, in Skripten und in Werkzeugen. Es basiert auf derselben Engine (V8) wie Chrome, hat aber kein DOM, sondern Module für Dateien, Netzwerk und Betriebssystem.

Teil des Kurses JavaScript

Kapitel 34 von 40 im Kurs JavaScript (Abschnitt „Node.js“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Node.js führt JavaScript außerhalb des Browsers aus, auf Servern, in Skripten und in Werkzeugen. Es basiert auf derselben Engine (V8) wie Chrome, hat aber kein DOM, sondern Module für Dateien, Netzwerk und Betriebssystem.

Installieren und starten

Lade Node.js (empfohlen: die LTS-Version) von nodejs.org. Prüfen im Terminal:

node --version
npm --version
node hallo.js
node                # interaktive Konsole (REPL)

Globale Objekte

console.log(typeof process, typeof global, typeof __dirname);
console.log(process.platform.length > 0, process.version.startsWith("v"));
console.log(process.argv.length >= 2);
console.log(typeof process.env.PATH, typeof process.cwd());
console.log(typeof setTimeout, typeof fetch, typeof structuredClone);

Ausgabe:

object object string
true true
true
string string
function function function
  • process.argv Argumente der Befehlszeile ([node, skript, ...])
  • process.env Umgebungsvariablen (process.env.PORT)
  • process.exit(code) beendet das Programm
  • __dirname, __filename Pfad der Datei (nur CommonJS; in ESM: import.meta.dirname)

Dateien lesen und schreiben

Das Modul fs (file system) hat synchrone und asynchrone Funktionen. Bevorzuge die Promise-Variante:

const fs = require("node:fs/promises");
const path = require("node:path");
const os = require("node:os");
 
async function main() {
  const ordner = await fs.mkdtemp(path.join(os.tmpdir(), "demo-"));
  const datei = path.join(ordner, "notiz.txt");
 
  await fs.writeFile(datei, "Zeile 1\nZeile 2\n", "utf8");
  await fs.appendFile(datei, "Zeile 3\n");
  const inhalt = await fs.readFile(datei, "utf8");
  console.log(inhalt.trim().split("\n"));
 
  const infos = await fs.stat(datei);
  console.log(infos.size, infos.isFile());
  console.log(await fs.readdir(ordner));
 
  await fs.rm(ordner, { recursive: true });
  console.log("aufgeräumt");
}
main().catch(console.error);

Ausgabe:

[ 'Zeile 1', 'Zeile 2', 'Zeile 3' ]
24 true
[ 'notiz.txt' ]
aufgeräumt

Pfade baust du mit path zusammen, nie mit +:

const path = require("node:path");
console.log(path.join("ordner", "unter", "datei.txt"));
console.log(path.basename("/a/b/bild.png"), path.extname("bild.png"), path.dirname("/a/b/bild.png"));
console.log(path.parse("/home/mia/text.md").name);

Ausgabe:

ordner/unter/datei.txt
bild.png .png /a/b
text

Argumente und Umgebung

const [, , ...args] = ["node", "skript.js", "--name=Mia", "--laut"];
const optionen = Object.fromEntries(
  args.filter(a => a.startsWith("--")).map(a => a.slice(2).split("=")).map(([k, v = true]) => [k, v])
);
console.log(optionen);
console.log(process.env.UNBEKANNT ?? "Standardwert");

Ausgabe:

{ name: 'Mia', laut: true }
Standardwert

Für ernsthafte Programme nimmst du util.parseArgs (eingebaut) oder Pakete wie commander.

Ein einfacher Webserver

import { createServer } from "node:http";
 
const server = createServer((anfrage, antwort) => {
  console.log(anfrage.method, anfrage.url);
  antwort.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
  antwort.end("Hallo vom Server!");
});
 
server.listen(3000, () => console.log("Läuft auf http://localhost:3000"));

Starte mit node server.mjs und öffne http://localhost:3000. In der Praxis nimmt man dafür Frameworks wie Express, Fastify oder Hono.

Streams

Streams verarbeiten große Daten stückweise, ohne alles in den Speicher zu laden:

const { Readable, Transform } = require("node:stream");
const { pipeline } = require("node:stream/promises");
 
const gross = new Transform({
  transform(chunk, _enc, cb) { cb(null, chunk.toString().toUpperCase()); },
});
const ausgabe = [];
pipeline(Readable.from(["hallo ", "welt"]), gross, async function (quelle) {
  for await (const teil of quelle) ausgabe.push(teil.toString());
}).then(() => console.log(ausgabe.join("")));

Ausgabe:

HALLO WELT

Events

Viele Node-Objekte senden Ereignisse über EventEmitter:

const { EventEmitter } = require("node:events");
class Chat extends EventEmitter {}
const raum = new Chat();
raum.on("nachricht", (von, text) => console.log(`${von}: ${text}`));
raum.once("start", () => console.log("Chat gestartet"));
raum.emit("start");
raum.emit("start");
raum.emit("nachricht", "Mia", "Hallo!");

Ausgabe:

Chat gestartet
Mia: Hallo!

Prozesse starten

const { execFileSync } = require("node:child_process");
console.log(execFileSync("node", ["--version"]).toString().startsWith("v"));

Ausgabe:

true

Achtung

Baue Befehle nie durch Zusammenkleben von Nutzereingaben (exec("rm " + eingabe)). Nutze execFile/spawn mit Argumentliste, um Befehlseinschleusung zu verhindern.

Merke

  • Node.js führt JavaScript ohne Browser aus (kein DOM, dafür fs, http, process)
  • fs/promises und path für Dateien und Pfade
  • process.argv, process.env für Argumente und Umgebung
  • Streams für große Daten, EventEmitter für Ereignisse
  • Eingaben nie ungeprüft an Shell-Befehle hängen

Übungsaufgabe

Schreibe ein Skript, das eine Textdatei einliest, die Wörter zählt und das Ergebnis in eine neue Datei schreibt.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Zeichnen mit Canvas und Animation

Weiter: npm und Pakete

Alle Kapitel: JavaScript im Überblick