Introduction
Getting ready for a JavaScript interview? Asynchronous JavaScript interview questions are everywhere in technical interviews. Don’t worry – this guide covers everything you need to know about asynchronous JavaScript, from basic concepts to tricky interview scenarios.
What Makes JavaScript Asynchronous?
Here’s something that confuses many developers: JavaScript is single-threaded, but it can handle multiple tasks at once. How does this work?
The secret lies in how JavaScript engines work with browsers. While JavaScript itself runs on one thread, browsers provide extra tools that make async operations possible.
The Call Stack Explained
Think of the call stack as a stack of plates. When we call a function, it goes on top of the stack. When the function finishes, it gets removed from the top.
Basically call stack is where JavaScript keeps track of function calls. Functions are pushed onto the stack when called and popped off when they return. It’s synchronous — one task at a time.
Let’s see this in action:
function add(a, b) { console.log("add function called"); return a + b; } function calculate(a, b) { console.log("calculate function called"); return add(a, b); } function printTotal(a, b) { let total = calculate(a, b); console.log(total); } printTotal(4, 5);
When this code runs:
- printTotal(4, 5) goes on the call stack
- Inside printTotal, calculate(4, 5) goes on top
- Inside calculate, console goes on top, followed by add(4, 5)
- console finishes and gets removed
- add finishes and gets removed
- calculate finishes and gets removed
- console inside printTotal goes on top
- printTotal finishes and gets removed
This happens very fast, but it’s still one thing at a time. This step-by-step process ensures that functions are executed in the correct order, maintaining an organised and predictable flow of execution.
The Problem with Synchronous Code
Let’s understand why asynchronous JavaScript exists in the first place.
Imagine we’re building a web app that needs to fetch user data from an API. If JavaScript worked only synchronously, our code might look like this:
console.log("Starting app..."); let userData = fetchUserData(); // This takes 3 seconds console.log("User data:", userData); console.log("App ready!");
The problem? The entire webpage would freeze for 3 seconds while waiting for the API response. Users couldn’t click buttons, scroll, or do anything. This creates a terrible user experience.
Asynchronous Callbacks – The Solution
Asynchronous callbacks allow us to handle time-consuming tasks without freezing the browser. Instead of waiting for an operation to complete, we tell JavaScript: “Start this task, and when it’s done, call this function.”
Here’s how the same API call would work with async callbacks:
console.log("Starting app..."); fetchUserData((userData) => { console.log("User data:", userData); }); console.log("App ready!");
Now the output would be:
Starting app... App ready! User data: [object Object]
Notice how “App ready!” appears before the user data? That’s because the app doesn’t wait for the API call to finish.
1: How Does setTimeout Work?
This is probably the most asked question about asynchronous JavaScript. Let’s break it down:
console.log("Number 1"); setTimeout(() => { console.log("Number 2"); }, 2000); console.log("Number 3"); Output: Number 1 Number 3 Number 2
Why doesn’t “Number 2” come after “Number 1”? Here’s what happens:
- console.log("Number 1") runs immediately
- setTimeout starts a timer but doesn’t block the code
- console.log("Number 3") runs immediately
- After 2 seconds, “Number 2” finally prints
The key insight: setTimeout doesn’t pause your code. It schedules something to happen later.
2: What Happens with setTimeout(fn, 0)?
This question trips up many developers:
console.log("Start"); setTimeout(() => { console.log("Timeout"); }, 0); console.log("End");
Even with 0 milliseconds, you get:
Start End Timeout
Why? Because setTimeout always puts callbacks in the queue, even with 0 delay. The callback must wait for the call stack to be empty.
3: Multiple setTimeout Calls
If you have multiple setTimeout(fn, 0) calls in a row, how will they be executed in relation to other synchronous code?
console.log("Start"); setTimeout(() => console.log("Timer 1"), 0); setTimeout(() => console.log("Timer 2"), 0); setTimeout(() => console.log("Timer 3"), 0); console.log("End");
Output:
Start End Timer 1 Timer 2 Timer 3
All timers go to the same callback queue and execute in order, but only after all synchronous code finishes.
4: What About Nested Promises?
console.log("Start"); Promise.resolve() .then(() => { console.log("Promise 1"); return Promise.resolve(); }) .then(() => { console.log("Promise 2"); }); setTimeout(() => { console.log("Timeout"); }, 0); console.log("End");
Output:
Start End Promise 1 Promise 2 Timeout
Each .then() creates a new microtask, but they all run before any macrotasks.
5: Error Handling in Async Code
console.log("Start"); setTimeout(() => { console.log("Timeout"); }, 0); Promise.reject("Error!") .catch(() => { console.log("Caught error"); }); console.log("End");
Error handling with .catch() also uses the microtask queue.
Conclusion
Asynchronous JavaScript might seem complex, but it follows predictable rules. The event loop, queues, and Web APIs work together to keep your applications responsive.
Remember the key principle: JavaScript runs one thing at a time, but browsers provide tools to handle multiple operations without blocking your code.
For a more detailed explanation, you can visit the following link.
Top comments (0)