async await in javascript
Async Await in JavaScript - The Complete Guide
Hey everyone! Welcome back to Namaste JavaScript. Today we are going to study async await - the most awaited topic of this series!
If you are a JavaScript developer, you should definitely know async await. It will be useful for your daily coding as well as for your interviews.
What we will cover:
- What is async?
- What is await?
- How async await works behind the scenes
- Real-world examples with fetch API
- Error handling in async await
- Interview tips
- async await vs .then/.catch
What is Async?
async is a keyword that is used before a function to create an async function.
async function getData() {
// This is an async function
}
Important: An async function ALWAYS returns a promise!
There are two cases:
- If you return a promise - it returns that promise as is
- If you return a non-promise value - it wraps it in a promise and returns
async function getData() {
return "Namaste";
}
const dataPromise = getData();
console.log(dataPromise);
OUTPUT:
Promise { [[PromiseState]]: "fulfilled", [[PromiseResult]]: "Namaste" }
See? It returned a promise even though we returned a string! To get the actual value:
dataPromise.then((res) => console.log(res));
OUTPUT: Namaste
What is Await?
await is a keyword that can ONLY be used inside an async function.
You write await in front of a promise, and it resolves that promise:
const p = new Promise((resolve, reject) => {
resolve("Promise resolved value");
});
async function handlePromise() {
const val = await p;
console.log(val);
}
handlePromise();
OUTPUT: Promise resolved value
Key Point: Instead of p.then(), you write await p and the resolved value comes directly into the variable!
IMPORTANT: If you try to use await outside an async function, you'll get a syntax error:
// WRONG - This will throw error!
function getData() {
const val = await p; // SyntaxError!
}
OUTPUT: SyntaxError: await is only valid in async functions
The MAJOR Difference - Behind the Scenes
This is the most important part that most developers don't understand!
Let's create a promise that takes 10 seconds to resolve:
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Promise resolved value");
}, 10000);
});
Old Way - Using .then():
function getData() {
p.then((res) => console.log(res));
console.log("Namaste JavaScript");
}
getData();
OUTPUT: Namaste JavaScript // Printed IMMEDIATELY Promise resolved value // Printed after 10 seconds
JavaScript does NOT wait! It prints "Namaste JavaScript" first, then after 10 seconds prints the promise value.
New Way - Using async await:
async function handlePromise() {
const val = await p;
console.log("Namaste JavaScript");
console.log(val);
}
handlePromise();
OUTPUT: // Nothing for 10 seconds... // After 10 seconds: Namaste JavaScript Promise resolved value
MIND BLOWN! The program WAITED at the await line for 10 seconds!
With async await, the JavaScript engine appears to wait for the promise to resolve before moving to the next line!
Multiple Promises - The Interesting Part
Let's see what happens with two promises:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("P1 resolved");
}, 10000); // 10 seconds
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("P2 resolved");
}, 5000); // 5 seconds
});
async function handlePromise() {
console.log("Hello World");
const val1 = await p1;
console.log("Namaste JavaScript");
console.log(val1);
const val2 = await p2;
console.log("Namaste JavaScript 2");
console.log(val2);
}
handlePromise();
Question: P1 takes 10 seconds, P2 takes 5 seconds. What will happen?
OUTPUT: Hello World // Immediately // After 10 seconds (NOT 5!): Namaste JavaScript P1 resolved Namaste JavaScript 2 P2 resolved
Why? Even though P2 resolves in 5 seconds, the program waits at await p1 for 10 seconds first. By the time it reaches await p2, P2 is already resolved!
Now reverse the order:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve("P1 resolved"), 5000); // 5 seconds
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve("P2 resolved"), 10000); // 10 seconds
});
async function handlePromise() {
console.log("Hello World");
const val1 = await p1;
console.log("Namaste JavaScript");
console.log(val1);
const val2 = await p2;
console.log("Namaste JavaScript 2");
console.log(val2);
}
handlePromise();
OUTPUT: Hello World // Immediately // After 5 seconds: Namaste JavaScript P1 resolved // After 10 seconds (5 more seconds): Namaste JavaScript 2 P2 resolved
Now the behavior is different! First batch prints after 5 seconds, second batch after 10 seconds.
How It ACTUALLY Works Behind the Scenes
Here's the truth that most developers don't know:
JavaScript does NOT actually wait! The call stack is NOT blocked.
What happens is:
- handlePromise() goes into call stack
- Executes until it hits
await p1 - Function execution SUSPENDS (not waits!)
- handlePromise() is removed from call stack
- Call stack is FREE for other operations
- After promise resolves, handlePromise() comes BACK to call stack
- Resumes execution from where it left
Key Insight: The function execution is suspended, not the JavaScript engine. The call stack remains free, so your page doesn't freeze!
Real World Example - Fetch API
Let's make an actual API call:
const API_URL = "https://api.github.com/users/akshaymarch7";
async function handlePromise() {
const data = await fetch(API_URL);
const jsonValue = await data.json();
console.log(jsonValue);
}
handlePromise();
OUTPUT:
{
login: "akshaymarch7",
id: 12345,
name: "Akshay Saini",
bio: "Founder NamasteDev",
...
}
How fetch works:
fetch()returns a Promise- When resolved, gives a Response object
- Response has a body (ReadableStream)
response.json()is ALSO a Promise!- When resolved, gives the actual JSON data
That's why we need TWO awaits!
Error Handling - Try Catch
With .then/.catch we used .catch(). With async await, we use try-catch:
async function handlePromise() {
try {
const data = await fetch(API_URL);
const jsonValue = await data.json();
console.log(jsonValue);
} catch (err) {
console.log(err);
}
}
handlePromise();
OUTPUT (if API fails): TypeError: Failed to fetch
Alternative way - using .catch() on the async function itself:
async function handlePromise() {
const data = await fetch(API_URL);
const jsonValue = await data.json();
console.log(jsonValue);
}
handlePromise().catch((err) => console.log(err));
OUTPUT (if API fails): TypeError: Failed to fetch
Both ways work! Use whichever you prefer.
Async Await vs .then/.catch
Important: async await is just syntactic sugar over .then/.catch!
Behind the scenes, JavaScript uses the same promise mechanisms. The only difference is how you WRITE the code.
Old way with .then/.catch:
function getData() {
fetch(API_URL)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((err) => console.log(err));
}
New way with async await:
async function getData() {
try {
const response = await fetch(API_URL);
const data = await response.json();
console.log(data);
} catch (err) {
console.log(err);
}
}
OUTPUT: (Both produce same result!)
{ login: "akshaymarch7", ... }
Why async await is better:
- No callback chaining needed
- Code looks synchronous, easier to read
- Easier to debug
- Line 2 only executes after Line 1's promise resolves
Interview Tips
Q: What is async await?
"async is a keyword used to create async functions. Async functions ALWAYS return a promise. await is a keyword that can ONLY be used inside async functions. It is used to handle promises - we write await in front of a promise and it resolves it. async await is syntactic sugar over .then/.catch - it makes asynchronous code look synchronous and easier to read."
Q: Does JavaScript actually wait at await?
"No! JavaScript does not actually wait. The function execution is SUSPENDED at the await line, and the function is removed from the call stack. The call stack remains free for other operations. Once the promise resolves, the function comes back to the call stack and resumes from where it left."
Q: Can await be used outside async function?
"No! await can ONLY be used inside an async function. Using it outside will throw a SyntaxError."
Quick Recap
// async - creates async function, always returns promise
async function getData() {
return "value"; // Wrapped in promise automatically
}
// await - only inside async, resolves promise
async function handlePromise() {
const val = await somePromise;
console.log(val);
}
// Error handling with try-catch
async function handlePromise() {
try {
const val = await somePromise;
} catch (err) {
console.log(err);
}
}
// Real world fetch example
async function fetchData() {
const response = await fetch(URL);
const data = await response.json();
return data;
}
OUTPUT Summary: - async function always returns Promise - await suspends function execution (not JS engine!) - Call stack is NOT blocked - Use try-catch for error handling - Syntactic sugar over .then/.catch
Key Points to Remember
- async keyword creates an async function
- Async function ALWAYS returns a promise
- await can ONLY be used inside async function
- await suspends function execution, not JS engine
- Call stack is NOT blocked - page won't freeze
- Use try-catch for error handling
- async await is syntactic sugar over promises
- Makes async code look synchronous and readable
Keep coding, keep learning!
Post a Comment