How to Pass a JavaScript Interview: Top Advanced-Level Questions
An interview for a Senior or Middle JavaScript developer position is not just a syntax check. Interviewers want to see a deep understanding of the language's mechanisms, especially in the Node.js environment. In this article, we will break down key topics that often cause difficulties and provide code examples to help you confidently answer even the trickiest questions.
1. Closures and Lexical Environment
The question about closures is a classic. But at an advanced level, it's important not just to give a definition, but to show how closures work with let, const, and in loops.
Question: What will the following code output and why?
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100);}// Output: 3, 3, 3The problem is that var has function scope, not block scope. By the time the callbacks are executed, the loop has already finished, and i equals 3. The solution is to use let (which creates a new binding on each iteration) or wrap the call in a closure:
for (var i = 0; i < 3; i++) { (function(j) { setTimeout(() => console.log(j), 100); })(i);}// Output: 0, 1, 2In Node.js, closures are actively used to create private variables and function factories. For example, when writing middleware:
function createLogger(prefix) { return function(message) { console.log(`[${prefix}] ${message}`); };}const infoLog = createLogger('INFO');infoLog('Server started'); // [INFO] Server started2. Event Loop and Microtasks
Understanding the event loop is one of the main evaluation criteria. Interviewers like to give tasks on the order of asynchronous code execution.
Question: In what order will the console.log statements execute?
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
process.nextTick(() => console.log('4'));
console.log('5');
// Output: 1, 5, 4, 3, 2Explanation:
console.log('1')andconsole.log('5')are synchronous and execute first.process.nextTickis a microtask with the highest priority. It executes immediately after the current phase completes.Promise.thenis also a microtask, but with a slightly lower priority thannextTick.setTimeout(fn, 0)is a macrotask, executed in the next tick of the Event Loop.
For Node.js, it's important to remember process.nextTick and setImmediate. The difference is that nextTick executes before any I/O, while setImmediate executes after.
3. Promises and Async Iterators (Async/Await)
An advanced level implies the ability to work with promise chains, error handling, and parallel execution.
Question: How do you handle multiple asynchronous requests to execute them in parallel but wait for all results?
const fetchData = (id) => { return new Promise((resolve) => { setTimeout(() => resolve(`Data for 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); // ['Data for ID: 1', 'Data for ID: 2', 'Data for ID: 3']}
getAllData();Important nuance: Promise.all rejects the entire promise at the first error. If you need to get all results (even with errors), use Promise.allSettled. This is a common topic in interviews in the context