Promises and async/await

HighIntermediateJavascript
Quick Answer

Promises and async/await use the same async model, but production pitfalls show up in accidental serialization, missing cancellation, and error paths that escape the right boundary.

Answer

Short version

A Promise represents a future result. async/await is a cleaner way to consume Promises. Same engine behavior, different readability style, but the production pitfall is assuming await is always clearer when it may accidentally serialize independent work.

Question

Answer

Do async functions return Promises?

Yes, always.

Does await block the whole app?

No. It pauses only that async function.

Does await change event-loop priority?

No. Promise continuation still resumes as microtasks.

Three interview checks people often confuse.
JAVASCRIPT
function fetchUser(id) {
  return Promise.resolve({ id, name: 'Ada' });
}

// Promise style
fetchUser(1)
  .then(user => user.name)
  .then(name => console.log(name))
  .catch(console.error);

// async/await style
async function run() {
  try {
    const user = await fetchUser(1);
    console.log(user.name);
  } catch (err) {
    console.error(err);
  }
}
run();
                  

Most important practical rule: avoid accidental serialization

JAVASCRIPT
// ❌ Sequential (slow if independent)
const a = await fetch('/a').then(r => r.json());
const b = await fetch('/b').then(r => r.json());

// ✅ Parallel (faster)
const [a2, b2] = await Promise.all([
  fetch('/a').then(r => r.json()),
  fetch('/b').then(r => r.json())
]);
                  

Need

Preferred API

Why

All must succeed

Promise.all

Fast-fails on first rejection.

Need every outcome

Promise.allSettled

Get success+failure results together.

First success wins

Promise.any

Useful for fallback mirrors/CDNs.

First settled wins

Promise.race

Timeout or first-responder patterns.

Choose combinator by business behavior, not habit.
JAVASCRIPT
// Cancellation pattern with fetch
const controller = new AbortController();

const req = fetch('/search?q=react', { signal: controller.signal });
controller.abort(); // cancel stale request

req.catch(err => {
  if (err.name === 'AbortError') return;
  throw err;
});
                  

Practical scenario
Autocomplete requests fire on each keystroke. You debounce input, cancel stale requests, and only render the latest resolved result to avoid flicker and race bugs.

Common pitfalls

  • Using await inside loops when calls are independent.
  • Forgetting terminal error handling.
  • Assuming Promise cancellation exists automatically.

Still so complicated?

Promise is the contract for future data. await is just cleaner punctuation when reading that contract.

Summary
  • Promises and async/await are the same async model.
  • Use try/catch (or .catch) consistently.
  • Parallelize independent work with Promise.all.
  • Use cancellation for stale UI requests.
Similar questions
Guides
Preparing for interviews?

Use the relevant interview-question hub first, then move into a concrete study plan before targeted company sets.