async and await keyword
Before the async/await keywords, we handled promises like this:
const p = new Promise((resolve, reject) => resolve("resolved promise"));
p.then((res) => {
console.log(res);
});
console.log("hello");
JavaScript doesn't "suspend" execution when handling promises. It immediately runs synchronous code first (like console.log("hello")), while the promise is resolved in the background. The .then() callback is scheduled to run asynchronously, meaning it will be executed later, after the current synchronous code finishes and the call stack is empty. The event loop handles this, ensuring non-blocking behavior, so the promise result (like "resolved promise") gets logged after "hello".
async Function
When you define a function with async, you're telling JavaScript that this function will work with promises.
If you return a value directly (e.g., a number or a string) from an async function, it’s automatically wrapped in a resolved promise.
If you return a promise, it’s returned as-is.
Example:
async function example() {
return 42; // JavaScript wraps this in a resolved promise automatically
}
example().then(result => console.log(result)); // Logs 42
This is equivalent to:
async function example() {
return Promise.resolve(42);
}
So no matter what, an async function always returns a promise.
await Keyword
await is used inside an async function to pause the function's execution until the promise you're waiting for is either:
Resolved (successful) — then it continues with the value of the resolved promise.
Rejected (failed) — then it throws an error (which you can catch using try...catch).
While waiting for the promise to resolve, JavaScript can still do other things, so your application doesn’t get blocked.
Let's break down how the JavaScript engine works with your code:
Promise Creation p1 and p2:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise resolve");
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise resolve");
}, 2000);
});
Here, a new promise p1 and p2 are created. It will be resolved with the value "promise resolve" after 1 seconds and 2 seconds .
Async Function (handlePromise):
async function handlePromise() {
const res1 = await p1; // p1 is not defined, so this will throw an error.
const res2 = await p2; // This is correct.
console.log(res1); // This line is executed after res1 is resolved.
console.log(res2); // This line is executed after res2 is resolved.
}
handlePromise();
How JavaScript Handles the await Keyword:
When the await keyword is encountered:
The execution of the handlePromise() function is paused at the line where the await is called.
The JavaScript engine does not block the entire thread. Instead, it puts the current async function on hold and allows other synchronous tasks to run in the event loop.
Step-by-Step Breakdown:
Start of handlePromise():
- The function is called, and execution begins.
First await on p1:
The engine encounters await p1.
It will pause here and check if p1 is resolved or rejected.
If p1 is a promise, it will wait for it to resolve. If p1 isn't yet resolved, the engine will continue processing other tasks in the event loop (for example, handling other callbacks, events, or even rendering).
Second await on p2:
Once p1 resolves, the function will continue, and the next await p2 is encountered.
It will wait for p2 to resolve (in this case, it will resolve after 2 seconds).
console.log() statements:
- After both p1 and p2 are resolved, the code will print res1 and res2 to the console.
Visualizing the Flow:
Start of handlePromise()
|--> Encounter await p1 -> Pause execution of handlePromise
|--> While waiting for p1, other tasks (like rendering) can run
|--> Once p1 resolves, move to next line of code
|--> Encounter await p2 -> Pause again while waiting for p2 to resolve
|--> After 2 seconds, p2 resolves
|--> Now execute console.log(res1) and console.log(res2)
Handling Errors with try...catch
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise 1 resolved");
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise 2 resolved");
}, 2000);
});
async function handlePromise() {
try {
const res1 = await p1; // This will resolve after 1 second
const res2 = await p2; // This will resolve after 2 seconds
console.log(res1); // prints "promise 1 resolved"
console.log(res2); // prints "promise 2 resolved"
} catch (error) {
console.log("Error:", error); // If any promise fails, this will catch the error
}
}
handlePromise();
If any of the promises in the await expressions (like await p1 or await p2) were to reject or an error occurred, the execution of the handlePromise function would immediately jump to the catch block.
simulate an error by changing p2 like this:
const p2 = new Promise((resolve, reject) => { setTimeout(() => { reject("promise 2 rejected"); }, 2000); });
In this case, the catch block would catch the rejection error.
Flow with try...catch
The function handlePromise() is called.
It enters the try block.
The first await p1 pauses the execution for 1 second, waiting for p1 to resolve.
After p1 resolves, it moves to the next line (await p2), which waits for p2 to resolve after 2 seconds.
If both promises resolve without issues, res1 and res2 are logged, and the function finishes execution.
If either promise rejects or an error occurs, the control jumps to the catch block, and the error is logged.
Multiple await Statements in side async function
If you have several async operations in sequence, you can use multiple await statements. Each one will pause the execution until the promise is settled.
Example:
async function processData() {
const data1 = await p1(); // Wait for first async operation
const data2 = await p2(); // Wait for second async operation
console.log(data1, data2); // After both promises are resolved, log the results
}
processData();
If you want to run multiple async operations at the same time (concurrently), you don't need to wait for each one before starting the next. Instead, you can start them all, then use await on the promises all at once.