JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicsjavascriptPromises & Async/Await
PrevNext
javascript
intermediate
20 min read

Promises & Async/Await

async
async-await
asynchronous
callbacks
concurrency
error-handling
microtasks
promise-all
promise-race
promises

Promises represent eventual completion or failure of async operations with three states (pending, fulfilled, rejected), and async/await provides syntactic sugar for writing promise-based code that reads like synchronous code.

Key Points

1Promise States

Pending (initial), fulfilled (succeeded with a value), or rejected (failed with a reason). Once settled, the state is permanent.

2Async/Await

Syntactic sugar over promises — async functions return promises, await pauses until settlement, and try/catch handles rejections.

3Promise Static Methods

all() fails fast on first rejection, allSettled() reports all outcomes, race() settles with the fastest, any() needs at least one success.

4Sequential vs Parallel

await in a loop runs sequentially; Promise.all() runs in parallel. Choosing correctly is a common performance question.

5Microtask Priority

Promise callbacks run as microtasks before setTimeout macrotasks — understanding this execution order is key for predicting async code behavior.

What You'll Learn

  • Understand Promise states and chaining with .then(), .catch(), and .finally()
  • Use async/await effectively and know how it relates to promises
  • Choose between Promise.all, allSettled, race, and any based on the use case

Deep Dive

Promises are the foundation of modern asynchronous JavaScript. A Promise is an object representing a value that may not be available yet but will be resolved at some point in the future (or rejected with an error).

Promise States

A promise is always in one of three states: pending (initial state, operation not yet complete), fulfilled (operation succeeded, promise has a value), or rejected (operation failed, promise has a reason/error). Once a promise is fulfilled or rejected, it is "settled" and its state cannot change again.

Promise Chaining

.then(onFulfilled, onRejected) handles the result and returns a new promise, enabling chaining. .catch(onRejected) is shorthand for .then(undefined, onRejected) and catches rejections from anywhere earlier in the chain. .finally(onFinally) runs cleanup code regardless of outcome — it receives no arguments and passes through the previous result. A critical pitfall: forgetting to return a value or promise inside .then() breaks the chain — the next .then() receives undefined.

Async/Await

async functions always return a promise. The await keyword pauses execution of the async function until the promise settles, then returns the fulfilled value (or throws the rejection reason). Error handling uses try/catch blocks. Under the hood, async/await compiles to promise chains — it's syntactic sugar, not a new mechanism. await can only be used inside async functions (or at the top level of ES modules).

Promise Static Methods

Four static methods handle multiple promises with different strategies:

  • Promise.all(iterable): Resolves when all promises fulfill, returning an array of values in order. Rejects immediately if any promise rejects — use when all results are required.
  • Promise.allSettled(iterable): Waits for all promises to settle (fulfill or reject). Returns an array of {status, value} or {status, reason} objects. Never rejects — use when you need all results regardless of individual failures.
  • Promise.race(iterable): Settles with the first promise to settle, whether fulfilled or rejected. Common use case: implementing timeouts by racing a fetch against a delay timer.
  • Promise.any(iterable): Resolves with the first fulfilled promise. Only rejects if all promises reject, throwing an AggregateError containing all rejection reasons. Use when you need at least one success.

Sequential vs Parallel Execution

Using await in a loop executes promises sequentially — each waits for the previous to complete. For parallel execution, start all promises first, then await them: const results = await Promise.all([fetch(url1), fetch(url2)]). This is a common interview question and a real performance consideration.

Microtask Queue

Promise callbacks (.then, .catch, .finally) are scheduled as microtasks, which run before macrotasks (like setTimeout). This means Promise.resolve().then(() => console.log('A')) always runs before setTimeout(() => console.log('B'), 0), regardless of their order in the code.

Common Pitfalls

Forgetting .catch() or try/catch in async functions leaves rejections unhandled — Node.js terminates on unhandled rejections by default. Creating promises without returning them from .then() creates "fire and forget" operations that swallow errors silently. Calling await on non-promise values works fine (returns the value immediately) but is unnecessary.

Key Interview Distinction

Promise.all fails fast on the first rejection. Promise.allSettled never fails — it reports all outcomes. Promise.race settles with whoever finishes first (success or failure). Promise.any needs at least one success. Knowing when to use each is a commonly tested concept.

Fun Fact

Promises were not invented by JavaScript — they originated in 1976 as 'futures' in a paper by Daniel P. Friedman. JavaScript adopted them from the Promises/A+ specification, a community standard that libraries like Bluebird and Q implemented before ES6 made them native in 2015.

Continue Learning

Event Loop & Runtime

intermediate

Closures

intermediate

Practice What You Learned

What are Promises in JavaScript and how do they work?
mid
async
A Promise is an object representing the eventual completion or failure of an asynchronous operation. It has three states: pending, fulfilled, or rejected, and provides .then(), .catch(), and .finally() methods for handling results.
How do async/await work and how do they relate to Promises?
mid
async
async/await is syntactic sugar over Promises. An async function always returns a Promise, and await pauses execution until a Promise resolves, making asynchronous code look and behave more like synchronous code.
What are Promise.all, Promise.race, Promise.allSettled, and Promise.any, and when do you use each?
mid
async
Promise.all resolves when all promises succeed (fails fast on first rejection). Promise.race resolves/rejects with the first settled promise. Promise.allSettled waits for all to settle regardless of outcome. Promise.any resolves with the first fulfilled promise (ignores rejections unless all fail).
How do you implement data polling in JavaScript?
mid
async
Data polling repeatedly fetches data at fixed intervals using setInterval or recursive setTimeout. Recursive setTimeout is preferred because it waits for the previous request to complete before scheduling the next one, preventing request pile-up on slow networks.
How would you implement a simplified Promise from scratch?
senior
promise-impl
A Promise implementation requires managing three states (pending/fulfilled/rejected), storing callbacks via then(), executing them asynchronously when the state transitions, and supporting chaining by returning new Promises from then().
How would you implement Promise.all and Promise.race from scratch?
senior
async
Promise.all takes an iterable of promises and returns a single promise that resolves with an array of all results (preserving order) or rejects with the first rejection. Promise.race returns a promise that settles with the first promise to settle, whether fulfilled or rejected.
Previous
Arrays
Next
Closures
PrevNext