JavaScript Interview Questions 16-20 (Promises, Async/Await, Event Loop)
Welcome to Part 4 of our JavaScript interview preparation series. If you have made it this far, you are doing excellent work. We are now entering the realm of Asynchronous JavaScript.
This is often considered the most challenging part of the language for learners because it requires thinking about time—code that doesn't happen now, but happens later. We will cover Promises, the modern syntax of async/await, and the engine behind it all: the Event Loop. We will break these down into simple, relatable concepts so you can explain them with confidence.
16. What are promises in JavaScript?
A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Before Promises, we relied heavily on callbacks, which often led to messy nested code (known as "callback hell"). Promises allow us to write cleaner code by chaining actions.
Analogy: Imagine you are at a busy burger restaurant. You place an order and pay. The cashier gives you a buzzer. That buzzer is a Promise. It is not the burger (the data), but it is a guarantee that eventually, one of two things will happen:
- The buzzer goes off, and you get your burger (Success/Resolve).
- The waiter tells you they ran out of buns and refunds you (Failure/Reject).
While you hold the buzzer, you can go find a table or check your phone. You are not stuck standing at the counter waiting for the meat to cook.
const orderBurger = new Promise((resolve, reject) => {
const isKitchenOpen = true;
if (isKitchenOpen) {
// Simulate cooking time
setTimeout(() => {
resolve("Burger is ready!");
}, 1000);
} else {
reject("Kitchen is closed.");
}
});
// Consuming the Promise
orderBurger
.then((message) => {
console.log("Success:", message);
})
.catch((error) => {
console.log("Error:", error);
});
Sample Output (after 1 second):
Success: Burger is ready!
17. What are the states of a JavaScript Promise?
A Promise can be in one of three distinct states. Once a Promise changes from Pending to either Fulfilled or Rejected, it is considered "settled," and its state cannot change again.
- Pending: The initial state. The operation has not completed yet. (Holding the buzzer, waiting).
- Fulfilled (Resolved): The operation completed successfully, and the promise now holds a result value. (Buzzer flashes, you get the burger).
- Rejected: The operation failed, and the promise now holds an error reason. (Kitchen closed, no burger).
const checkState = new Promise((resolve, reject) => {
// Currently in 'Pending' state inside this function
const success = true;
if (success) {
resolve("Operation Successful"); // Transitions to 'Fulfilled'
} else {
reject("Operation Failed"); // Transitions to 'Rejected'
}
});
console.log(checkState);
// Depending on the runtime, this might print Promise { <pending> }
// or Promise { 'Operation Successful' } immediately if sync.
Tip: In an interview, simply listing the three states is good, but explaining that a settled promise is immutable (cannot change state again) shows deeper understanding.
18. What is async/await and how does it work?
Introduced in ES2017 (ES8), async/await is syntactic sugar built on top of Promises. It allows you to write asynchronous code that looks and behaves like synchronous code, making it much easier to read and debug.
- async: Placed before a function, it ensures the function returns a Promise.
- await: Can only be used inside an async function. It pauses the execution of the function until the Promise is resolved.
Analogy: Imagine reading a book (your code). Using .then() is like putting a bookmark in and jumping to the appendix to read the end of the story. Using await is like simply pausing your reading while someone fetches you a coffee, and then you continue reading the very next line once the coffee arrives.
// 1. Function returning a Promise
function fetchUser() {
return new Promise((resolve) => {
setTimeout(() => resolve("Alice"), 1000);
});
}
// 2. The Old Way (.then)
// fetchUser().then(name => console.log(name));
// 3. The Modern Way (Async/Await)
async function getUser() {
console.log("Fetching...");
// Execution pauses here until fetchUser resolves
const name = await fetchUser();
console.log("User found: " + name);
}
getUser();
Sample Output:
Fetching...
// (waits 1 second)
User found: Alice
19. What is the event loop in JavaScript?
JavaScript is single-threaded, meaning it can only do one thing at a time. However, it handles asynchronous tasks (like clicking buttons, timers, or fetching data) using the Event Loop.
The Event Loop monitors two things: the Call Stack (where code runs) and the Callback Queue (where waiting tasks sit). If the Call Stack is empty, the Event Loop takes the first item from the Queue and pushes it onto the Stack to run.
Analogy: Think of a waiter (JS Engine) in a restaurant with one table.
- Call Stack: The waiter handling the current customer's order.
- Web APIs: The kitchen cooking the food (this happens in the background).
- Callback Queue: A line of cooked dishes ready to be served.
- Event Loop: The rule that says, "The waiter can only serve a dish from the queue if they are currently doing nothing else."
console.log("1. Start");
// setTimeout is sent to Web APIs (kitchen), then Callback Queue
setTimeout(() => {
console.log("2. Timeout finished");
}, 0);
console.log("3. End");
// Output order might surprise beginners!
// The 'Timeout' waits in the queue until the stack ('End') is clear.
Sample Output:
1. Start
3. End
2. Timeout finished
20. What is the difference between synchronous and asynchronous JavaScript?
This distinction is about blocking vs non-blocking code.
| Feature | Synchronous | Asynchronous |
|---|---|---|
| Execution | Sequential (Line by line) | Simultaneous (in background) |
| Behavior | Blocking (Stops everything) | Non-Blocking (Lets code continue) |
| Examples | Loops, variable assignment | API requests, Timers, Events |
Analogy:
- Synchronous: A phone call. You must stay on the line and listen. You cannot do anything else until the call ends.
- Asynchronous: Sending a text message. You hit send, then you put your phone in your pocket and go for a walk. You check it later when it buzzes.
// Synchronous (Blocking)
console.log("Start Sync");
for(let i=0; i<1000000000; i++) {} // Long loop freezes the browser
console.log("End Sync");
// Asynchronous (Non-Blocking)
console.log("Start Async");
setTimeout(() => console.log("Async Task Done"), 1000);
console.log("End Async");
You have now conquered the asynchronous pillars of JavaScript! Understanding how the Event Loop manages your code and using Promises or Async/Await to handle data flow is what separates a novice from a professional developer. Take a moment to appreciate how much you have learned—these are complex topics that power the modern web.