Introduction to async/await
async/await is a modern way to handle asynchronous operations in JavaScript. Introduced in ES2017 (ES8), it allows developers to write asynchronous code in a manner that looks and behaves like synchronous code.
The main goal of async/await is to improve readability and maintainability of code that involves Promises or other asynchronous tasks.
Why use async/await?
Before async/await, developers relied heavily on callback functions or Promises, which could lead to complex and hard-to-read code, especially when chaining multiple asynchronous operations.
async/await simplifies this process by making asynchronous code easier to read and write, resembling regular synchronous code.
Async Functions
The async keyword is used to define an asynchronous function. It makes the function always return apromise. If the function returns a value, JavaScript automatically wraps it in a resolved promise.
async function f() {
return 1;
}Here’s what the code does step by step:
- The
asynckeyword beforefunction f()means the function is asynchronous. - Inside the function, the value
1is returned. However, because the function is asynchronous, JavaScript automatically wraps this value in a resolved promise. - When calling
f(), it will return a promise that resolves to the value1.
To see the output, you can call the function and use .then() to handle the resolved promise:
f().then(result => console.log(result)); // Output: 1 Key Points- An
asyncfunction always returns a promise. - If a value is returned from the function, it’s automatically wrapped in a resolved promise.
- You can use
.then()to access the returned value.
Async functions are a great way to write asynchronous code in a more readable and cleaner way.
Note : You can use the async keyword in a function even if the function does not use await. However, the reverse is not true—await can only be used inside an async function.
Basic Syntax of async/await
- The async keyword is used to define a function that returns a Promise. It allows the use of the await keyword inside the function.
- The await keyword is used to pause the execution of an async function until the Promise it awaits is resolved or rejected.
// Defining an async function
async function fetchData() {
let data = await getDataFromAPI(); // Pauses here until the Promise is resolved
console.log(data); // Executes after the Promise resolves
}Using async/await with Promises
async/await is built on top of Promises, so you can use it seamlessly with existing Promise-based code. Here's an example:
// Example with async/await
function fetchDataFromAPI() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data fetched successfully");
}, 2000);
});
}
async function displayData() {
try {
let data = await fetchDataFromAPI();
console.log(data); // Output: "Data fetched successfully"
} catch (error) {
console.error("Error fetching data:", error);
}
}
displayData();Error Handling in async/await
Errors in async/await functions can be caught using a try...catch block. This makes error handling more intuitive compared to using the .catch() method with Promises.
async function fetchDataWithError() {
try {
let response = await fetch("https://nonexistentapi.com/data");
let data = await response.json();
console.log(data);
} catch (error) {
console.error("Error occurred:", error);
}
}
fetchDataWithError();Async/Await vs Promise Chaining
Example Without
async/await (Using Promise Chaining)
function fetchUserData(userId) {
return fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then(response => response.json());
}
function fetchUserPosts(userId) {
return fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
.then(response => response.json());
}
// Fetch user data, then their posts
fetchUserData(1)
.then(user => {
console.log("User:", user);
return fetchUserPosts(user.id);
})
.then(posts => {
console.log("Posts:", posts);
})
.catch(error => {
console.error("Error:", error);
});
Example With async/await
async function fetchUserDetails(userId) {
try {
const userResponse = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
const user = await userResponse.json();
console.log("User:", user);
const postsResponse = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`);
const posts = await postsResponse.json();
console.log("Posts:", posts);
} catch (error) {
console.error("Error:", error);
}
}
fetchUserDetails(1);
Comparison:- Readability:
async/awaitmakes the code easier to read and follow compared to promise chaining. - Error Handling: A single
try...catchblock can handle all errors in theasync/awaitversion, while in promise chaining, you need proper.catch()placement. - Scalability:
async/awaitscales better when dealing with multiple asynchronous operations in sequence.
Pros and Cons of async/await
Pros:
- Improves code readability and maintainability.
- Reduces callback hell.
- Handles complex asynchronous workflows more elegantly.
Cons:
- Cannot be used at the top level of code (must be inside an async function).
- Async functions return Promises, which may still require chaining in some cases.