JavaScript · Async JS

Async JS Interview Questions
With Answers & Code Examples

6 carefully curated Async JS interview questions with working code examples and real interview gotchas.

Practice Interactively →← All Categories
6 questions2 beginner4 core0 advanced
Q1Beginner

Explain Promises — states, chaining, and error handling.

💡 Hint: pending → fulfilled/rejected; .then chains; .catch handles errors

A Promise is a value that may be available now or later. States: pending → fulfilled / rejected. Once settled, immutable.

fetch('/api/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err))
  .finally(() => setLoading(false));

Combinators: Promise.all (all must resolve), Promise.allSettled (wait all), Promise.race (first settles), Promise.any (first resolves).

Practice this question →
Q2Core

How does async/await work under the hood?

💡 Hint: Syntactic sugar over Promises; await pauses the function, not the thread

async/await is syntactic sugar over Promises. An async function always returns a Promise. await pauses only that function's execution.

async function fetchUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error('Not found');
    return await res.json();
  } catch (err) {
    console.error(err);
  }
}
💡 Parallel fetching: use Promise.all([fetch(a), fetch(b)]) instead of sequential awaits — ~2x faster.
Practice this question →
Q3Beginner

What is callback hell and how do you avoid it?

💡 Hint: Pyramid of doom — nested callbacks; solve with Promises/async-await

Deeply nested callbacks make code hard to read, debug, and maintain.

// ❌ Callback hell
getUser(id, (user) => {
  getPosts(user, (posts) => {
    getComments(posts[0], (comments) => { ... });
  });
});

// ✅ Async/await
const user = await getUser(id);
const posts = await getPosts(user);
const comments = await getComments(posts[0]);
Practice this question →
Q4Core

What are Promise combinators and when do you use each?

💡 Hint: all=all resolve, allSettled=wait all, race=first settles, any=first resolves
  • Promise.all() — waits for ALL to resolve. Rejects immediately if ANY rejects. Use when all must succeed.
  • Promise.allSettled() — waits for ALL to settle (resolve OR reject). Never rejects itself. Use when you need all results regardless of failure.
  • Promise.race() — settles with the FIRST settled promise (resolve or reject). Use for timeout patterns.
  • Promise.any() — resolves with the FIRST resolved promise. Rejects only if ALL reject. Use for fallback/redundancy.
const fast = fetch('/fast');   // 100ms
const slow = fetch('/slow');   // 500ms
const bad  = fetch('/broken'); // 200ms, rejects

await Promise.all([fast, slow]);    // ✅ 500ms (waits for both)
await Promise.all([fast, bad]);     // ❌ rejects at 200ms

const results = await Promise.allSettled([fast, slow, bad]);
// [{status:'fulfilled', value:...}, ..., {status:'rejected', reason:...}]

await Promise.race([fast, slow]);   // resolves at 100ms with fast result

await Promise.any([bad, fast]);     // resolves at 100ms (ignores bad)

// Timeout pattern with race:
const withTimeout = (p, ms) => Promise.race([
  p,
  new Promise((_, r) => setTimeout(() => r(new Error('Timeout')), ms))
]);
💡 allSettled is your safety net — it always resolves, making it great for "fire multiple requests, report all results" patterns.
Practice this question →
Q5Core

What is queueMicrotask() and when should you use it?

💡 Hint: Schedule a function in the microtask queue — runs after current sync, before next macrotask

queueMicrotask(fn) adds a callback directly to the microtask queue — the same queue that Promise callbacks use.

// Functionally equivalent:
Promise.resolve().then(() => console.log('A'));
queueMicrotask(() => console.log('B'));
// A, B — FIFO within the microtask queue

console.log('sync');
queueMicrotask(() => console.log('microtask'));
setTimeout(() => console.log('macrotask'), 0);
console.log('sync end');
// Order: sync → sync end → microtask → macrotask

Advantages over Promise.resolve().then():

  • No Promise overhead — slightly more performant
  • More explicit — clearly states "schedule as microtask"
  • Doesn't create a Promise chain
// Real use case: batch state updates
let pending = false;
function scheduleRender() {
  if (pending) return;
  pending = true;
  queueMicrotask(() => {
    pending = false;
    renderDOM(); // runs once after all sync mutations
  });
}
💡 Use queueMicrotask when you want something to run "ASAP but async" — after current sync code finishes, before any I/O or timers fire.
Practice this question →
Q6Core

How do you handle unhandled Promise rejections?

💡 Hint: They crash Node.js 15+ — always attach .catch() or try/catch; use global handlers as last resort

An unhandled rejection occurs when a Promise rejects with no .catch() or try/catch handler.

// ❌ Unhandled
const p = Promise.reject(new Error('oops'));
// Browser: warning in console; Node.js 15+: crashes process

// ✅ Always handle
async function fetchData() {
  try {
    return await fetch('/api');
  } catch (err) {
    if (err.status === 404) return null; // handle known
    throw err;                           // re-throw unknown
  }
}

// ✅ At call site
fetchData().catch(err => console.error(err));

// Global handlers (last resort / monitoring)
// Browser
window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled:', event.reason);
  event.preventDefault(); // suppress browser logging
});

// Node.js
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection:', reason);
  process.exit(1); // recommended in production
});
💡 Never rely on global handlers for correctness — they're for logging/monitoring. Fix the root cause by ensuring every async operation is wrapped in try/catch or has .catch().
Practice this question →

Other JavaScript Interview Topics

Core JSFunctionsObjectsArrays'this' KeywordError HandlingModern JSPerformanceDOM & EventsBrowser APIs

Ready to practice Async JS?

Get AI feedback on your answers, predict code output, and fix real bugs.

Start Free Practice →