JavaScript - Async and Await
Because JavaScript is an asynchronous, single-threaded programming language, it can execute lengthy actions without causing the main thread to stall. A contemporary JavaScript component called async feature helps programmers create asynchronous code more effectively and cleanly by preventing callback hell and improving readability.
We'll go into great detail about the async and await keywords in this blog article, outlining their uses, advantages, and how they improve the readability of JavaScript asynchronous programming.
1. An overview of await and async
In ECMAScript 2017 (ES8), the async and await keywords were added to JavaScript to make working with promises easier. They make it possible to construct asynchronous code that functions and seems like synchronous code, which facilitates reading and debugging.
async Function
An async function is a function declared with the async keyword. It allows you to use the await keyword within the function body to wait for asynchronous operations to complete.
Example of async Function:
async function fetch_Data() {
return "Data received!";
}
fetch_Data().then((data) => console.log(data)); // Output: Data received!
The async function always returns a promise. If the function returns a value, the promise will resolve with that value. If it throws an error, the promise will be rejected with that error.
await Keyword
The await keyword is used to pause the execution of an async function until a promise is resolved. It can only be used inside an async function.
Example with await:
async function fetch_Data() {
let response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
let data = await response.json();
console.log(data);
}
fetch_Data();
In this example, the function pauses at the await fetch(...) line until the promise returned by fetch() is resolved, and then proceeds to the next line after the data is received.
2. Why Use async and await?
The main benefits of using async and await include:
Readability: Asynchronous code written with async/await looks more like synchronous code, making it easier to read and understand.
Error Handling: You can handle errors in asynchronous functions using standard try...catch blocks instead of dealing with the .catch() method on promises.
Avoiding Callback Hell: async/await helps avoid deeply nested callbacks that make code hard to read and maintain.
Example of Nested Promises (Callback Hell):
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json())
.then((data) => {
console.log(data);
return fetch('https://jsonplaceholder.typicode.com/posts/2');
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));
Refactor with async/await:
async function fetchMultipleData() {
try {
let response1 = await fetch('https://jsonplaceholder.typicode.com/posts/1');
let data1 = await response1.json();
console.log(data1);
let response2 = await fetch('https://jsonplaceholder.typicode.com/posts/2');
let data2 = await response2.json();
console.log(data2);
} catch (error) {
console.error(error);
}
}
fetchMultipleData();
The refactored code is more readable, with a flat structure that is easier to follow and maintain.
3. Error Handling with async and await
Handling errors with promises usually requires the .catch() method, which can make code less readable. With async/await, error handling can be done using the standard try...catch block.
Example:
async function fetch_Data() {
try {
let response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
if (!response.ok) {
throw new Error("Network response was not ok");
}
let data = await response.json();
console.log(data);
} catch (error) {
console.error('There has been a problem with your fetch operation:', error);
}
}
fetch_Data();
The try...catch block helps catch any error that occurs during the execution of the await statements, including network errors or issues with the response.
4. Multiple await Statements
You can use multiple await statements in an async function, but be aware that each await pauses the function until the promise is resolved. This can slow down your code if you're waiting for multiple independent promises.
Example with Multiple await:
async function fetch_Data() {
let response1 = await fetch('https://jsonplaceholder.typicode.com/posts/1');
let data1 = await response1.json();
let response2 = await fetch('https://jsonplaceholder.typicode.com/posts/2');
let data2 = await response2.json();
console.log(data1, data2);
}
fetch_Data();
In this case, await waits for the first request to complete before sending the second request. This works but can be inefficient if the requests are independent of each other.
5. Improving Performance with Promise.all()
If you have multiple asynchronous tasks that don’t depend on each other, you can run them concurrently using Promise.all(). This method allows you to wait for all promises to resolve without waiting for one to complete before starting the next.
Example Using Promise.all():
async function fetchMultipleData() {
try {
let [response1, response2] = await Promise.all([
fetch('https://jsonplaceholder.typicode.com/posts/1'),
fetch('https://jsonplaceholder.typicode.com/posts/2'),
]);
let data1 = await response1.json();
let data2 = await response2.json();
console.log(data1, data2);
} catch (error) {
console.error(error);
}
}
fetchMultipleData();
Here, both fetch requests are sent simultaneously, and the function waits until both promises are resolved, improving the performance compared to sequential execution.
6. Async Functions and the Event Loop
The event loop in JavaScript is essential for controlling asynchronous code. An await causes an async function to halt its execution so that other code can continue. The function resumes execution at the point when the awaited promise resolves. Because they don't stall, async functions are very effective.
7. async in Arrow Functions
You can use the async keyword in arrow functions as well.
Example:
const fetchData = async () => {
let response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
let data = await response.json();
console.log(data);
};
fetch_Data();
This allows you to use the more concise syntax of arrow functions along with async/await.
8. Conclusion
JavaScript asynchronous programming has been transformed by async and await. By eschewing the intricate chains of promises, they improve the readability, debugging, and overall cleanliness of your code. You may handle asynchronous activities in JavaScript more efficiently by combining async functions with error handling, performance enhancements like Promise.all(), and a well-organized code structure.
Writing more effective and efficient code requires knowing async and await, two concepts that are crucial to current JavaScript development.