Promises vs async/await: What Is the Difference?
Learn how async/await relates to Promises, why they share the same mechanism, and how error handling differs.
Expected Interview Answer
Promises and async/await are the same underlying mechanism for handling asynchronous results β async/await is syntactic sugar built on top of Promises that lets you write asynchronous code that reads like synchronous code, without changing how the microtask queue or the Promise state machine actually works underneath.
A Promise is an object representing an eventual value, with .then(), .catch(), and .finally() methods used to chain reactions once it settles into fulfilled or rejected. Chaining several .then() calls is powerful but can become hard to read when branching logic or multiple awaited results are involved. An async function always returns a Promise, and the await keyword inside it pauses that function's execution (without blocking the thread) until the awaited Promise settles, then resumes with the resolved value or throws the rejection as a catchable exception. This lets you use ordinary try/catch for error handling and write sequential-looking code for what is still fundamentally asynchronous, non-blocking behavior. The two are interoperable: you can await a .then()-based Promise chain, and an async function is just a Promise producer that other code can still consume with .then().
- Reads like synchronous code, reducing nested .then() callback chains
- Lets you use standard try/catch for asynchronous error handling
- Interoperates fully with existing Promise-based APIs
- Makes sequential and conditional async logic significantly easier to follow
AI Mentor Explanation
A Promise is like a token handed to a fan after ordering food at the stadium, which they can attach instructions to β "when ready, bring it to seat 12" β without standing at the counter. async/await is like a runner who is told to physically wait at the counter, in a way that does not block anyone else's service, and only walks back to the seat once the order is actually ready, carrying it directly. Both approaches deliver the same food from the same kitchen process, but the runner's way reads like a simple step-by-step task list instead of a chain of attached instructions. That same-mechanism, different-syntax relationship is exactly how async/await relates to Promises.
Step-by-Step Explanation
Step 1
Promise created and returned
An asynchronous operation (fetch, timer, DB call) returns a Promise representing its eventual result.
Step 2
await pauses the async function
Inside an async function, await suspends that functionβs execution without blocking the thread, until the Promise settles.
Step 3
Value returned or exception thrown
On fulfillment, await yields the resolved value; on rejection, it throws, catchable via try/catch.
Step 4
async function itself returns a Promise
Callers of the async function can still use .then()/.catch() on its return value if desired.
What Interviewer Expects
- Clear statement that async/await is syntax over the same Promise mechanism, not a different concurrency model
- Correct explanation of how try/catch replaces .catch() with async/await
- Awareness that await does not block the thread, only pauses that function
- Mention of interoperability between Promise chains and async/await
Common Mistakes
- Claiming async/await runs on a separate thread or is somehow faster
- Forgetting to wrap awaited calls in try/catch, silently swallowing rejections
- Sequentially awaiting independent Promises instead of using Promise.all for concurrency
- Believing async/await eliminates the microtask queue instead of using it
Best Answer (HR Friendly)
βPromises and async/await do the exact same thing under the hood β handling something that will finish later, like a network request. Promises use .then() chains, while async/await lets you write that same asynchronous code so it reads top to bottom like normal code, with regular try/catch for errors, which most people find easier to follow.β
Code Example
// Promise chain
function loadUserThen(id) {
return fetch(`/api/users/${id}`)
.then(res => res.json())
.catch(err => {
console.error('Failed to load user', err)
throw err
})
}
// async/await, same underlying Promise mechanism
async function loadUserAwait(id) {
try {
const res = await fetch(`/api/users/${id}`)
return await res.json()
} catch (err) {
console.error('Failed to load user', err)
throw err
}
}Follow-up Questions
- How would you run several independent async calls concurrently instead of sequentially?
- What happens if you forget to await an async function call?
- How does error handling differ between .catch() and try/catch with async/await?
- Can you mix Promise.then() chains and async/await in the same codebase?
MCQ Practice
1. What does async/await fundamentally change about JavaScript's concurrency model?
async/await is syntactic sugar over Promises; the underlying event loop and microtask behavior is unchanged.
2. How do you handle a rejected Promise inside an async function using await?
A rejected awaited Promise throws inside the async function, catchable with a standard try/catch block.
3. What does an async function always return?
Calling an async function always yields a Promise, even if the function body returns a plain value.
Flash Cards
Is async/await a different concurrency model than Promises? β No β it is syntax built on the same Promise mechanism.
How do you catch errors with async/await? β Standard try/catch around the awaited call.
Does await block the thread? β No β it pauses only that async function without blocking other code.
What does an async function return? β Always a Promise, regardless of the returned value.