So bestehst du das JavaScript-Vorstellungsgespräch: Top-Fragen für Fortgeschrittene
Ein Vorstellungsgespräch für eine Position als Senior- oder Middle-JavaScript-Entwickler ist nicht nur eine Überprüfung der Syntax. Interviewer möchten ein tiefes Verständnis der Funktionsweise der Sprache sehen, insbesondere in der Node.js-Umgebung. In diesem Artikel analysieren wir die wichtigsten Themen, die oft Schwierigkeiten bereiten, und geben Codebeispiele, die dir helfen, selbst die kniffligsten Fragen souverän zu beantworten.
1. Closures und lexikalische Umgebung
Die Frage nach Closures ist ein Klassiker. Aber auf fortgeschrittenem Niveau ist es wichtig, nicht nur eine Definition zu geben, sondern zu zeigen, wie Closures mit let, const und in Schleifen funktionieren.
Frage: Was gibt der folgende Code aus und warum?
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100);}// Ausgabe: 3, 3, 3Das Problem ist, dass var einen funktionalen und keinen blockbezogenen Gültigkeitsbereich hat. Zum Zeitpunkt des Aufrufs der Callbacks ist die Schleife bereits beendet und i ist gleich 3. Die Lösung ist die Verwendung von let (erzeugt bei jeder Iteration eine neue Bindung) oder das Verpacken des Aufrufs in ein Closure:
for (var i = 0; i < 3; i++) { (function(j) { setTimeout(() => console.log(j), 100); })(i);}// Ausgabe: 0, 1, 2In Node.js werden Closures aktiv verwendet, um private Variablen und Funktionsfabriken zu erstellen. Zum Beispiel beim Schreiben von Middleware:
function createLogger(prefix) { return function(message) { console.log(`[${prefix}] ${message}`); };}const infoLog = createLogger('INFO');infoLog('Server gestartet'); // [INFO] Server gestartet2. Event Loop und Microtasks
Das Verständnis der Ereignisschleife ist eines der Hauptbewertungskriterien. Interviewer geben gerne Aufgaben zur Reihenfolge der Ausgabe von asynchronem Code.
Frage: In welcher Reihenfolge werden die console.log-Aufrufe ausgeführt?
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
process.nextTick(() => console.log('4'));
console.log('5');
// Ausgabe: 1, 5, 4, 3, 2Analyse:
console.log('1')undconsole.log('5')sind synchron und werden zuerst ausgeführt.process.nextTickist ein Microtask mit der höchsten Priorität. Er wird sofort nach Abschluss der aktuellen Phase ausgeführt.Promise.thenist ebenfalls ein Microtask, jedoch mit einer etwas niedrigeren Priorität alsnextTick.setTimeout(fn, 0)ist ein Macrotask und wird im nächsten Tick des Event Loops ausgeführt.
Für Node.js ist es wichtig, sich an process.nextTick und setImmediate zu erinnern. Der Unterschied besteht darin, dass nextTick vor jeglicher Ein-/Ausgabe ausgeführt wird, während setImmediate danach ausgeführt wird.
3. Promises und asynchrone Iteratoren (Async/Await)
Das fortgeschrittene Niveau setzt die Fähigkeit voraus, mit Promise-Ketten, Fehlerbehandlung und paralleler Ausführung zu arbeiten.
Frage: Wie verarbeitet man mehrere asynchrone Anfragen, um sie parallel auszuführen, aber auf alle Ergebnisse zu warten?
const fetchData = (id) => { return new Promise((resolve) => { setTimeout(() => resolve(`Daten für ID: ${id}`), id * 100); });};
async function getAllData() { const ids = [1, 2, 3]; const promises = ids.map(id => fetchData(id)); const results = await Promise.all(promises); console.log(results); // ['Daten für ID: 1', 'Daten für ID: 2', 'Daten für ID: 3']}
getAllData();Wichtige Nuance: Promise.all lehnt das gesamte Promise beim ersten Fehler ab. Wenn du alle Ergebnisse (auch mit Fehlern) erhalten möchtest, verwende Promise.allSettled. Dies ist ein häufiges Thema in Vorstellungsgesprächen im Kontext