π¨ JavaScript Β· Topic 18 of 20
Asynchronous JavaScript β JavaScript Questions with Answers
30 practice questions on Asynchronous JavaScript, each with the correct answer and a clear explanation of why it is right. Read through them as revision notes, or take this topic as an interactive quiz to test yourself.
0 easy Β· 14 medium Β· 16 hard Β· Part of JavaScript: The language of the web - basics to advanced, 20 topics.
Medium questions (14)
Q1. medium
What does 'JavaScript is single-threaded' mean?
- A It executes one statement at a time on one call stack - long tasks block everything
- B It can only run one file
- C It uses one CPU core for rendering
- D It cannot handle events
Answer: A β It executes one statement at a time on one call stack - long tasks block everything
There is one main thread, so a slow loop freezes the whole page including clicks and animations. Asynchronous APIs exist so waiting does not block that thread.
Single-threadedCall stack
Q2. medium
What is the output ORDER?
console.log("A");
setTimeout(() => console.log("B"), 0);
console.log("C");
- A A C B - the timer callback waits until the synchronous code finishes
- B A B C
- C B A C
- D A C, then B after a long delay
Answer: A β A C B - the timer callback waits until the synchronous code finishes
Even with 0 ms, the callback is queued and can only run once the call stack is empty. This is the clearest demonstration of the event loop.
Event loopsetTimeout
Q7. medium
What is a callback in asynchronous code?
- A A function you hand to an async operation, to be run when it finishes
- B A function that calls itself
- C A returned value
- D An error type
Answer: A β A function you hand to an async operation, to be run when it finishes
Rather than blocking to wait for a result, you say 'call this when done'. Timers, events and older APIs all use this pattern.
Callbacks
Q9. medium
What is the error-first callback convention?
- A The callback's FIRST parameter is an error (null when successful), the second is the data
- B Errors are thrown instead
- C The callback returns errors
- D There is no convention
Answer: A β The callback's FIRST parameter is an error (null when successful), the second is the data
Standard in Node.js: fs.readFile(path, (err, data) => { if (err) return handle(err); ... }). It forces callers to consider failure first.
Node.jsCallbacks
Q10. medium
What does setInterval do, and how do you stop it?
const id = setInterval(tick, 1000);
clearInterval(id);
- A Repeats a callback every N ms until clearInterval(id) is called
- B Runs once after N ms
- C Cannot be stopped
- D Pauses the page
Answer: A β Repeats a callback every N ms until clearInterval(id) is called
Always keep the returned id and clear it when done, or the interval keeps running (and leaking) after the component or page section is gone.
setIntervalclearInterval
Q13. medium
What is the call stack?
- A The list of functions currently executing - each call pushes a frame, each return pops one
- B A queue of events
- C Browser memory
- D The DOM tree
Answer: A β The list of functions currently executing - each call pushes a frame, each return pops one
Error stack traces are printouts of this stack. Overflowing it with runaway recursion gives 'Maximum call stack size exceeded'.
Call stackStack trace
Q16. medium
What does requestAnimationFrame do?
function loop() {
move();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
- A Schedules a callback to run just before the next repaint - ideal for smooth animation
- B Runs code every second
- C Loads images
- D Requests data from a server
Answer: A β Schedules a callback to run just before the next repaint - ideal for smooth animation
It syncs with the display refresh (about 60 fps) and pauses in background tabs, making it far better than setInterval for animation.
AnimationrAF
Q18. medium
Which of these are handled by Web APIs rather than the JS engine itself?
- A setTimeout, fetch, DOM events, geolocation
- B for loops and arithmetic
- C Array methods
- D String operations
Answer: A β setTimeout, fetch, DOM events, geolocation
The engine runs your code; the browser provides timers, networking and events. They do the waiting off-thread and queue callbacks when ready.
Web APIsRuntime
Q20. medium
What is the difference between synchronous and asynchronous code?
- A Synchronous blocks until it finishes; asynchronous starts an operation and continues, handling the result later
- B Async code is always faster
- C Sync code runs on another thread
- D There is no difference
Answer: A β Synchronous blocks until it finishes; asynchronous starts an operation and continues, handling the result later
Async does not mean parallel in JavaScript - it means 'do not block the thread while waiting'. The waiting happens elsewhere; your callback runs later on the same thread.
Concurrency
Q22. medium
What does queueMicrotask(fn) do?
- A Schedules fn in the microtask queue - it runs before timers but after current sync code
- B Runs fn immediately
- C Runs fn after 1 ms
- D Creates a Web Worker
Answer: A β Schedules fn in the microtask queue - it runs before timers but after current sync code
It gives the same priority as promise callbacks, useful for deferring work to just after the current task without waiting for a timer.
Microtasks
Q24. medium
How do you pause for 2 seconds in modern async code?
const sleep = ms => new Promise(r => setTimeout(r, ms));
await sleep(2000);
- A await new Promise(r => setTimeout(r, 2000))
- B sleep(2000)
- C wait(2)
- D thread.sleep(2000)
Answer: A β await new Promise(r => setTimeout(r, 2000))
JavaScript has no built-in sleep. Wrapping setTimeout in a promise gives a clean, non-blocking delay usable with await.
Promisesasync/await
Q26. medium
What does clearTimeout(id) do?
- A Cancels a pending timer before it fires
- B Stops all timers
- C Resets the clock
- D Nothing after the timer is set
Answer: A β Cancels a pending timer before it fires
Essential for debouncing: each new keystroke clears the previous pending timer so only the final one runs.
clearTimeoutDebounce
Q28. medium
Which pattern reads most clearly for sequential async steps today?
- A async/await with try/catch
- B Nested callbacks
- C Long .then() chains only
- D Synchronous XMLHttpRequest
Answer: A β async/await with try/catch
await makes asynchronous code read top-to-bottom like synchronous code, with familiar try/catch error handling - built on promises underneath.
async/awaitReadability
Q30. medium
Why does console.log show the OLD value here?
let data = null;
fetchData(d => data = d);
console.log(data);
- A The callback has not run yet - the log executes before the async work completes
- B fetchData is broken
- C data is const
- D console.log is async
Answer: A β The callback has not run yet - the log executes before the async work completes
The single most common async misunderstanding. You must USE the data inside the callback (or await the promise) rather than reading it immediately after.
Async timingCommon mistakes
Hard questions (16)
Q3. hard
Does setTimeout(fn, 1000) guarantee the callback runs in exactly 1 second?
- A No - it runs after AT LEAST 1 second, once the stack is free
- B Yes, exactly
- C It runs immediately
- D It never runs
Answer: A β No - it runs after AT LEAST 1 second, once the stack is free
The delay is a minimum. If synchronous code is still running (or other callbacks are queued), the timer waits longer. Never rely on precise timing.
setTimeoutTiming
Q4. hard
What is the event loop?
- A The mechanism that moves queued callbacks onto the call stack whenever the stack is empty
- B A for loop over events
- C A browser animation
- D The DOM event system
Answer: A β The mechanism that moves queued callbacks onto the call stack whenever the stack is empty
Web APIs (timers, network) handle waiting off-thread and push their callbacks into a queue. The event loop constantly checks: is the stack empty? If so, take the next callback.
Event loopTask queue
Q5. hard
Which runs FIRST when the stack empties: a promise callback or a setTimeout callback?
setTimeout(() => console.log("timeout"));
Promise.resolve().then(() => console.log("promise"));
// promise, then timeout
- A The promise - MICROtasks have priority over macrotasks (timers)
- B setTimeout, because it was scheduled first
- C Whichever was written first
- D They run simultaneously
Answer: A β The promise - MICROtasks have priority over macrotasks (timers)
The microtask queue (promises, queueMicrotask) is fully drained before the next macrotask (setTimeout, events). This is why .then() consistently beats setTimeout(0).
MicrotasksMacrotasks
Q6. hard
What is the output order?
console.log(1);
setTimeout(() => console.log(2));
Promise.resolve().then(() => console.log(3));
console.log(4);
- A 1 4 3 2
- B 1 2 3 4
- C 1 4 2 3
- D 1 3 4 2
Answer: A β 1 4 3 2
Synchronous first (1, 4), then microtasks (3), then macrotasks (2). This exact question appears in countless interviews.
Event loopOrdering
Q8. hard
What is 'callback hell'?
getUser(id, (u) => {
getOrders(u, (o) => {
getItems(o, (i) => {
// deeply nested...
});
});
});
- A Deeply nested callbacks for sequential async steps, hard to read and to error-handle
- B Too many functions in a file
- C A browser crash
- D Using callbacks at all
Answer: A β Deeply nested callbacks for sequential async steps, hard to read and to error-handle
Each step nests inside the previous one, drifting rightward (the 'pyramid of doom') with error handling duplicated at every level. Promises and async/await were created to flatten this.
Callback hellPromises
Q11. hard
Why can a long synchronous loop freeze the page?
- A It occupies the single thread, so rendering, clicks and timers cannot run until it finishes
- B It uses too much memory
- C The browser blocks loops
- D It does not freeze anything
Answer: A β It occupies the single thread, so rendering, clicks and timers cannot run until it finishes
The browser cannot repaint or process events while your code holds the thread. Break heavy work into chunks (setTimeout/requestIdleCallback) or move it to a Web Worker.
BlockingPerformance
Q12. hard
What is a Web Worker?
const w = new Worker("worker.js");
w.postMessage(data);
w.onmessage = (e) => console.log(e.data);
- A A script running on a SEPARATE thread, so heavy work does not block the UI
- B A server process
- C A type of callback
- D A browser extension
Answer: A β A script running on a SEPARATE thread, so heavy work does not block the UI
Workers communicate by messages and cannot touch the DOM, but they are ideal for parsing large files, image processing or heavy computation.
Web WorkersThreads
Q14. hard
What is the output?
function a() { b(); }
function b() { throw new Error("x"); }
try { a(); } catch (e) { console.log("caught"); }
- A caught - the error propagates DOWN the call stack to the nearest try/catch
- B An uncaught error
- C Nothing
- D SyntaxError
Answer: A β caught - the error propagates DOWN the call stack to the nearest try/catch
Synchronous errors bubble through the stack until a try/catch handles them. Asynchronous callbacks run on an empty stack, which is why try/catch cannot catch them.
Error propagationCall stack
Q15. hard
Why does this NOT catch the error?
try { setTimeout(() => { throw new Error("x"); }, 0); }
catch (e) { console.log("caught"); }
- A The callback runs later on a fresh stack, long after the try block completed
- B setTimeout cannot throw
- C The syntax is wrong
- D It does catch it
Answer: A β The callback runs later on a fresh stack, long after the try block completed
try/catch is strictly synchronous. Move it inside the callback, or use promises with .catch()/await.
Async errorstry/catch
Q17. hard
What is the output order?
setTimeout(() => console.log("t1"), 0);
setTimeout(() => console.log("t2"), 0);
Promise.resolve().then(() => console.log("p1")).then(() => console.log("p2"));
- A p1 p2 t1 t2 - ALL microtasks drain before any timer
- B t1 t2 p1 p2
- C p1 t1 p2 t2
- D t1 p1 t2 p2
Answer: A β p1 p2 t1 t2 - ALL microtasks drain before any timer
The chained .then also schedules a microtask, which runs in the same drain cycle - so both promise logs beat both timers.
MicrotasksEvent loop
Q19. hard
What is the output?
console.log("start");
for (let i = 0; i < 3; i++) setTimeout(() => console.log(i), 0);
console.log("end");
- A start end 0 1 2
- B start 0 1 2 end
- C start end 3 3 3
- D 0 1 2 start end
Answer: A β start end 0 1 2
Both logs run synchronously first; the three timer callbacks follow in order. let gives each its own i, so 0 1 2 (var would give 3 3 3).
Event loopClosures
Q21. hard
Why is nested async code better expressed with promises?
- A Promises flatten the nesting into a chain and centralise error handling in one .catch()
- B Promises are synchronous
- C Callbacks are unsupported
- D Promises are slower but prettier
Answer: A β Promises flatten the nesting into a chain and centralise error handling in one .catch()
Each callback level needed its own error check; a promise chain propagates rejections automatically to a single handler at the end.
PromisesCallback hell
Q23. hard
What happens if a microtask schedules another microtask endlessly?
- A The queue never empties, so the page freezes - timers and rendering never get a turn
- B The browser alternates fairly
- C It throws an error
- D Nothing happens
Answer: A β The queue never empties, so the page freezes - timers and rendering never get a turn
Microtasks are drained completely before anything else, so an infinite chain starves the event loop - worse than a long timer loop.
MicrotasksStarvation
Q25. hard
Why is a while loop the WRONG way to wait 2 seconds?
while (Date.now() - start < 2000) { }
- A It blocks the single thread completely - the page freezes and nothing renders
- B It is not accurate
- C It uses too much memory
- D It works fine
Answer: A β It blocks the single thread completely - the page freezes and nothing renders
This 'busy wait' burns CPU and prevents all rendering and input. Always yield with a timer or promise instead.
BlockingBusy waiting
Q27. hard
What is the output?
const start = Date.now();
setTimeout(() => console.log(Date.now() - start), 100);
for (let i = 0; i < 1e9; i++) { }
- A A number much LARGER than 100 - the blocking loop delays the callback
- B Exactly 100
- C 0
- D Nothing is printed
Answer: A β A number much LARGER than 100 - the blocking loop delays the callback
The timer becomes ready at 100 ms but must wait for the stack to clear. This proves timer delays are minimums, not guarantees.
BlockingTimers
Q29. hard
Is async code parallel?
- A No - it is CONCURRENT: operations overlap in waiting, but JS callbacks still run one at a time on the main thread
- B Yes, fully parallel
- C Only with promises
- D Only in Node.js
Answer: A β No - it is CONCURRENT: operations overlap in waiting, but JS callbacks still run one at a time on the main thread
Several network requests can be in flight simultaneously (the browser handles them), but your JavaScript callbacks are processed sequentially. True parallel JS requires Web Workers.
Concurrency vs parallelism