Can You Answer This Senior Level JavaScript Promise Interview Question?
Most interviewees failed on it.
What is the output of the following code?
const promise = new Promise((resolve, reject) => { console.log(1); setTimeout(() => { console.log("timerStart"); resolve("success"); console.log("timerEnd"); }, 0); console.log(2); }); promise.then((res) => { console.log(res); }); console.log(4);
Write your answer in comment before reading analysis ✍️
Analysis
This question often stumps junior JavaScript developers because it tests the understanding of asynchronous behavior in JavaScript. To understand the output, we need to look at how JavaScript handles synchronous and asynchronous tasks.
Synchronous vs Asynchronous Code
JavaScript runs code in two modes: synchronous (executed immediately) and asynchronous (executed later, usually after some event, like a timer or a network request, has finished). The JavaScript event loop ensures that synchronous tasks are executed first, followed by any pending asynchronous tasks.
Example:
console.log('start'); const promise1 = new Promise((resolve, reject) => { console.log(1) resolve(2) }) promise1.then(res => { console.log(res) }) console.log('end');
In this code:
- console.log('start') runs first.
- Inside the promise, console.log(1) runs next.
- Then, the resolve(2) happens, but the .then() block is asynchronous, so it doesn't execute immediately.
- Finally, console.log('end') runs before the result from the promise (console.log(res)).
So, the output is:
start -> 1 -> end -> 2.
Microtasks vs Macrotasks
JavaScript divides asynchronous tasks into microtasks and macrotasks. Here's how they work:
- Microtasks: These include promises. They are processed after the current synchronous code but before macrotasks.
- Macrotasks: These include tasks like setTimeout(). They are processed after microtasks.
Understanding the Original Code
Let’s break down the original code with this knowledge:
const promise = new Promise((resolve, reject) => { console.log(1); // (1) Synchronous, logs 1 setTimeout(() => { // (4) Asynchronous macrotask console.log("timerStart"); // (6) Logs "timerStart" resolve("success"); // (7) Resolves the promise console.log("timerEnd"); // (8) Logs "timerEnd" }, 0); console.log(2); // (2) Synchronous, logs 2 }); promise.then((res) => { console.log(res); // (5) Microtask, logs "success" }); console.log(4); // (3) Synchronous, logs 4
Breakdown of Execution:
- The promise is created, and the executor function is run synchronously.
- console.log(1) runs (output: 1).
- The setTimeout() call schedules a macrotask, but this does not run immediately.
- console.log(2) runs (output: 2).
- promise.then() adds a microtask, which will run after all synchronous code finishes.
- console.log(4) runs (output: 4).
- Now that all synchronous code is done, the microtask (from promise.then()) runs (output: "success").
- Finally, the macrotask (from setTimeout()) runs. console.log("timerStart") (output: "timerStart"), the promise resolves, and console.log("timerEnd") runs (output: "timerEnd").
Final Output:
1 2 4 success timerStart timerEnd
Finally
This interview question tests the interviewee's understanding of the event loop, microtasks, and macrotasks in JavaScript. If you understand how JavaScript schedules asynchronous tasks, you'll be able to predict the output of this code with confidence.
Write your answer in comment box ☑️