One of the most commonly asked JavaScript interview questions is:

What are async/await and how do they work?

Most developers can write:

JAVASCRIPT
async function fetchUsers() {
  const users = await getUsers();
}

But interviewers often go deeper:

  • Is async/await different from Promises?
  • Does await block the main thread?
  • How does await interact with the Event Loop?
  • Can multiple awaits run in parallel?
  • What happens when an error occurs?

Let's understand async/await from first principles.

1. Why Do We Need Async/Await?#

Consider fetching user data from an API.

Using callbacks:

JAVASCRIPT
getUser(function (user) {
  getPosts(user.id, function (posts) {
    getComments(posts[0].id, function (comments) {
      console.log(comments);
    });
  });
});

This quickly becomes:

Callback Hell

Problems:

  • Hard to read
  • Hard to debug
  • Difficult error handling
  • Nested code

Promises improved this:

JAVASCRIPT
getUser()
  .then(getPosts)
  .then(getComments)
  .then(console.log)
  .catch(console.error);

Better, but still chain-heavy.

Async/await was introduced to make asynchronous code look synchronous.

2. What is an Async Function?#

The async keyword transforms a function into an asynchronous function.

JAVASCRIPT
async function greet() {
  return "Hello";
}

Although it appears to return a string:

JAVASCRIPT
greet();

actually returns:

JAVASCRIPT
Promise { "Hello" }

Equivalent to:

JAVASCRIPT
function greet() {
  return Promise.resolve("Hello");
}

Example#

JAVASCRIPT
async function getMessage() {
  return "FrontendPrep";
}

console.log(getMessage());

Output:

JAVASCRIPT
Promise { "FrontendPrep" }

Important interview point:

Every async function always returns a Promise.

3. What is Await?#

await pauses execution inside an async function until a Promise settles.

Example:

JAVASCRIPT
async function fetchData() {
  const data = await getUsers();

  console.log(data);
}

Execution flow:

Call Function
      ↓
Wait For Promise
      ↓
Promise Resolves
      ↓
Continue Execution

Simple Example#

JAVASCRIPT
function delay() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("Done");
    }, 2000);
  });
}

async function run() {
  const result = await delay();

  console.log(result);
}

run();

Output after 2 seconds:

Done

Does Await Block JavaScript?#

A common interview question.

Many developers answer:

Yes

This is incorrect.

Wrong

await blocks JavaScript

Correct

await pauses only the current async function

The Event Loop continues running.

Example:

JAVASCRIPT
async function demo() {
  console.log("Start");

  await Promise.resolve();

  console.log("End");
}

demo();

console.log("Outside");

Output:

Start
Outside
End

If await blocked JavaScript:

Start
End
Outside

would appear.

It doesn't.

4. Async/Await Under the Hood#

Consider:

JAVASCRIPT
async function getUser() {
  const user = await fetch("/api/user");

  return user.json();
}

JavaScript roughly converts this into:

JAVASCRIPT
function getUser() {
  return fetch("/api/user").then((user) => {
    return user.json();
  });
}

Important interview point:

Async/await is syntax sugar over Promises.

Execution Order Interview Question#

What is the output?

JAVASCRIPT
console.log(1);

async function demo() {
  console.log(2);

  await Promise.resolve();

  console.log(3);
}

demo();

console.log(4);

Answer#

Output:

1
2
4
3

Why?

1 → Sync
2 → Sync
await → Pause function
4 → Sync
3 → Microtask Queue

5. Error Handling with Async/Await#

Promises:

JAVASCRIPT
fetchData().then(handleSuccess).catch(handleError);

Async/Await:

JAVASCRIPT
async function loadData() {
  try {
    const data = await fetchData();

    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

Cleaner and easier to read.

What Happens When Await Rejects?#

JAVASCRIPT
async function demo() {
  await Promise.reject("Failed");
}

Equivalent to:

JAVASCRIPT
throw "Failed";

The function immediately exits unless handled.

Example#

JAVASCRIPT
async function demo() {
  try {
    await Promise.reject("Error");

    console.log("Never runs");
  } catch (error) {
    console.log(error);
  }
}

Output:

Error

6. Optimization: Sequential vs. Parallel Awaits#

Consider:

JAVASCRIPT
const user = await getUser();
const posts = await getPosts();

Execution:

Get User
   ↓
Wait
   ↓
Get Posts
   ↓
Wait

Total time:

Time1 + Time2

Interview Optimization Question#

What is wrong here?

JAVASCRIPT
const users = await fetchUsers();
const posts = await fetchPosts();

If both requests are independent:

Unnecessary waiting

Better Solution#

JAVASCRIPT
const [users, posts] = await Promise.all([fetchUsers(), fetchPosts()]);

Execution:

Start Both Requests
         ↓
Wait Once
         ↓
Receive Results

Total time:

max(Time1, Time2)

instead of:

Time1 + Time2

Async/Await vs Promise.all#

Sequential

JAVASCRIPT
await task1();
await task2();
await task3();

Timeline:

Task1
 ↓
Task2
 ↓
Task3

Concurrent

JAVASCRIPT
await Promise.all([task1(), task2(), task3()]);

Timeline:

Task1
Task2
Task3
 ↓
Wait Once

Much faster.

7. Top-Level Await#

No.

Invalid:

JAVASCRIPT
function demo() {
  const data = await fetchUsers();
}

Error:

await is only valid in async functions

Top-Level Await#

Modern JavaScript allows:

JAVASCRIPT
const users = await fetchUsers();

inside ES modules.

Example:

users.js

const users = await fetch("/users");

export default users;

8. Async Function Execution Without Await#

JAVASCRIPT
async function demo() {
  return 10;
}

Perfectly valid.

Output:

JAVASCRIPT
Promise { 10 }

9. Common Interview Q&A#

Does Async/Await Replace Promises?#

No.

Async/await is built on top of Promises.

Promises still power everything underneath.

Does Await Create a New Thread?#

No.

JavaScript remains single-threaded.

The Event Loop handles scheduling.

Can Multiple Awaits Run Simultaneously?#

Not automatically.

This:

JAVASCRIPT
await task1();
await task2();

runs sequentially.

Use:

JAVASCRIPT
Promise.all();

for concurrency.

Can Async Functions Return Values?#

Yes.

JAVASCRIPT
async function getName() {
  return "John";
}

Actually returns:

JAVASCRIPT
Promise.resolve("John");

What Happens If an Async Function Throws?#

JAVASCRIPT
async function demo() {
  throw new Error("Failed");
}

Equivalent to:

JAVASCRIPT
return Promise.reject(new Error("Failed"));

Senior-Level Interview Answer#

Async/await is syntactic sugar built on top of Promises that allows asynchronous code to be written in a synchronous-looking manner. An async function always returns a Promise, and the await keyword pauses execution of the current async function until a Promise settles. Await does not block the JavaScript thread; it simply yields control back to the Event Loop. Under the hood, async/await is transformed into Promise chains. For independent asynchronous operations, Promise.all should be used to execute tasks concurrently and improve performance.

Common Interview Mistakes#

❌ "await blocks JavaScript."

Correct:

await pauses only the current async function.

❌ "async functions return values."

Correct:

async functions always return Promises.

❌ "async/await is different from Promises."

Correct:

async/await is built on top of Promises.

❌ "Multiple awaits run in parallel."

Correct:

Awaits are sequential unless explicitly parallelized.

Key Takeaways#

  • Syntactic Sugar: Built on top of Promises to write cleaner, synchronous-looking asynchronous code.
  • Execution Flow: An async function returns a Promise; await pauses execution until the Promise resolves.
  • Error Handling: Uses native try/catch blocks instead of .catch() chains for asynchronous operations.
  • Task Orchestration: Awaiting tasks sequentially can block execution; use Promise.all to run requests in parallel.
  • Top-Level Await: Supported in modern modules to pause importing modules until assets resolve.